在 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?

存储在 plist 中的数据在模拟器中有效,但在设备中无效

如何在保存在 Mongoose (ExpressJS) 之前在模型中格式化数据

如何在保存在 Mongoose (ExpressJS) 之前在模型中格式化数据