You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用FluentAssertions测试所有属性均已修改(无目标值限制)

解决方案:用FluentAssertions断言所有属性均与原状态不同

要实现所有属性都必须被修改(即每个属性值都与原对象的对应属性不同),你可以利用FluentAssertions的自定义成员验证逻辑,替代默认的等价性检查。

核心实现代码

通过BeEquivalentTo结合Using和ForAllMembers,为每个成员指定“不等于原对象对应值”的验证规则:

after.Should().BeEquivalentTo(before, options =>
    options.Using<object>(ctx => ctx.Subject.Should().NotBe(ctx.Expectation))
           .ForAllMembers());

代码解释

  • BeEquivalentTo(before):启动对象图等价性比较的基础框架
  • Using<object>(...):定义针对所有成员的自定义验证逻辑,要求当前成员的值(ctx.Subject)不等于原对象的对应成员值(ctx.Expectation)
  • ForAllMembers():将这个自定义规则应用到所有属性/字段上

适配你的测试案例

修改你提供的测试代码,用上述断言替换原来的NotBeEquivalentTo:

[Test]
public void ShouldFail_BecauseClassesAreEquivalent()
{
    var before = new MyClass { Apple = 1, Banana = 2 };
    var after = new MyClass2 { Apple = 1, Banana = 2 };

    // 所有属性都未修改,断言失败(符合预期)
    after.Should().BeEquivalentTo(before, options =>
        options.Using<object>(ctx => ctx.Subject.Should().NotBe(ctx.Expectation))
               .ForAllMembers());
}

[Test]
public void ShouldFail_BecauseClassesShouldHaveALlPropertiesModified_NotOnlyOne()
{
    var before = new MyClass { Apple = 1, Banana = 2 };
    var after = new MyClass2 { Apple = 100, Banana = 2 };

    // Banana属性未修改,断言失败(符合预期)
    after.Should().BeEquivalentTo(before, options =>
        options.Using<object>(ctx => ctx.Subject.Should().NotBe(ctx.Expectation))
               .ForAllMembers());
}

[Test]
public void ShouldWork_BecauseClassesDoHaveALlPropertiesModified()
{
    var before = new MyClass { Apple = 1, Banana = 2 };
    var after = new MyClass2 { Apple = 100, Banana = 200 };

    // 所有属性都已修改,断言通过(符合预期)
    after.Should().BeEquivalentTo(before, options =>
        options.Using<object>(ctx => ctx.Subject.Should().NotBe(ctx.Expectation))
               .ForAllMembers());
}

扩展:验证对象所有属性已被填充(与空状态对比)

针对你提到的“检查对象所有属性均已被填充”的场景,只需将原对象替换为空实例即可:

var emptyState = new MyClass2();
after.Should().BeEquivalentTo(emptyState, options =>
    options.Using<object>(ctx => ctx.Subject.Should().NotBe(ctx.Expectation))
           .ForAllMembers());

这样就能确保每个属性都不再是默认值(比如int类型的0),达到“所有属性已被填充”的验证目的。

注意事项

  • 该方案仅验证属性值与原状态不同,无法检测属性映射错误(比如把Apple的值映射到Banana),这部分如你所说,可通过代码评审覆盖
  • 如果需要针对特定类型做特殊处理(比如引用类型的null检查),可以修改Using的泛型类型并调整验证逻辑

内容的提问来源于stack exchange,提问作者rklec

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.16 10:48:18