在 FluentAssertions.Primitives.ObjectAssertions 的扩展方法中调用 Excluding 方法不起作用,但调用它正常工作
Posted
技术标签:
【中文标题】在 FluentAssertions.Primitives.ObjectAssertions 的扩展方法中调用 Excluding 方法不起作用,但调用它正常工作【英文标题】:Calling Excluding method in extension method for FluentAssertions.Primitives.ObjectAssertions does not work, but calling it normally works 【发布时间】:2019-12-14 19:31:28 【问题描述】:我已经开始在我的 REST 端点集成测试中使用 FluentAssertions
库。问题是我必须比较两个实体,但不包括它们的 _id
属性。这个属性是从我的IEntity
接口继承而来的。
public interface IEntity
[BsonId]
ObjectId _id get; set;
所以例如Log
类看起来像这样
[DataContract]
public class Log : IEntity
[BsonId]
public ObjectId _id get; set;
public string Message get; set;
在测试中我像这样比较它们并且它有效
retrieved.Should()
.BeEquivalentTo(expected, options => options.Excluding(member => member._id));
但是当我将此功能提取到扩展方法中以供重用时,它不起作用。它不会忽略_id
成员。
public static class ObjectAssertionExtensions
public static void BeEquivalentToExcludingId<TExpectation>(this ObjectAssertions objectAssertion, TExpectation expectation) where TExpectation : IEntity
objectAssertion.BeEquivalentTo(expectation, options => options.Excluding(member => member._id));
当我将通用扩展方法更改为特定类型 Log
时,它会正常工作。
我已经准备了最小的项目,例如here。
请问有没有办法让它工作,为什么它不能正常工作?我将尝试在 github 存储库中检查 FluentAssertions
的代码。谢谢。
【问题讨论】:
在BeEquivalentTo
中使用之前将expected
转换为IEntity
会有什么不同吗?
不,它给了我“消息:System.InvalidOperationException:没有找到要比较的成员。请指定一些要包含在比较中的成员或选择更有意义的断言。”
可能是github.com/fluentassertions/fluentassertions/issues/1077的情况。已在 master 中修复,但尚未发布。
【参考方案1】:
问题在于 Fluent Assertions 无法将泛型类型 T
的 _id
关联到具体类型 Log
的 _id
。
#1077 中报告了类似问题,#1087 已解决。 在撰写本文时,我们尚未发布包含此修复的新版本。
编辑 2019-08-10:
Fluent Assertions 5.8.0 已随修复程序一起发布。
【讨论】:
谢谢,我很期待新版本:)。【参考方案2】:首先,在ObjectAssertionsExtensions
中进行更改是有意义的
public static void BeEquivalentToExcludingId<TExpectation>(this ObjectAssertions objectAssertion,
TExpectation expectation) where TExpectation : IEntity
到
public static void BeEquivalentToExcludingId(this ObjectAssertions objectAssertion,
IEntity expectation)
我还将每个断言放入单独的测试中以定位问题。
事情的发生是因为 BeEquivalentToExcludingId
期望 IEntity
仅具有 _id
属性,但得到 Log
具有额外的 Message
属性。这让一切都出错了。如果它不会损害您的架构,只需将 IEntity
修改为 string Message
属性,它就会解决问题。所以,唯一的变化:
public interface IEntity
[BsonId]
ObjectId _id get; set;
string Message get; set;
解决问题。
更新:
考虑到您的评论,只需将要排除的成员设置为相同的值,调用BeEquivalentTo
并像这样设置实际值:
public static void BeEquivalentToExcludingId(this ObjectAssertions objectAssertion, IEntity expectation)
var subj = (IEntity)objectAssertion.Subject;
var subjId = subj._id;
var expId = expectation._id;
subj._id = ObjectId.Empty;
expectation._id = ObjectId.Empty;
objectAssertion.BeEquivalentTo(expectation);
subj._id = subjId;
expectation._id = expId;
这很hacky,但它可以工作。
【讨论】:
感谢您通过直接使用类型 IEntity 指出更好的扩展方法定义。但是,将 Message 和所有其他属性添加到 IEntity 中违背了它的目的,我最终会得到一个包含后代类的所有属性的类。所以这不是一个可行的解决方案。 @c0ntrol,不客气。但我相信它可以更整洁。以上是关于在 FluentAssertions.Primitives.ObjectAssertions 的扩展方法中调用 Excluding 方法不起作用,但调用它正常工作的主要内容,如果未能解决你的问题,请参考以下文章
在 React 应用程序中在哪里转换数据 - 在 Express 中还是在前端使用 React?