如何用Lambda函数创建NUnit约束以验证类实例属性一致性
实现NUnit自定义约束以清晰展示A类实例属性对比结果
1. 自定义NUnit约束类
继承NUnit的Constraint基类,实现自定义验证逻辑和失败消息输出,完全规避ToString的歧义问题:
using NUnit.Framework.Constraints; public class SameAAndBConstraint : Constraint { private readonly A _expectedInstance; public SameAAndBConstraint(A expected) { _expectedInstance = expected; } // 核心验证逻辑:精准对比PropertyA和PropertyB public override ConstraintResult ApplyTo<TActual>(TActual actual) { if (actual is not A actualInstance) { return new ConstraintResult(this, actual, ConstraintStatus.Failure); } bool matches = actualInstance.PropertyA.Equals(_expectedInstance.PropertyA) && actualInstance.PropertyB.Equals(_expectedInstance.PropertyB); return new ConstraintResult(this, actual, matches ? ConstraintStatus.Success : ConstraintStatus.Failure); } // 输出期望实例的属性详情 public override void WriteDescriptionTo(MessageWriter writer) { writer.Write($"instance of {typeof(A).Name} with PropertyA='{_expectedInstance.PropertyA}', PropertyB='{_expectedInstance.PropertyB}'"); } // 输出实际实例的属性详情 public override void WriteActualValueTo(MessageWriter writer) { if (ActualValue is A actualInstance) { writer.Write($"instance of {typeof(A).Name} with PropertyA='{actualInstance.PropertyA}', PropertyB='{actualInstance.PropertyB}'"); } else { base.WriteActualValueTo(writer); } } }
2. 封装便捷调用方法
通过静态扩展方法让测试代码更简洁:
using NUnit.Framework.Constraints; public static class AConstraintExtensions { public static SameAAndBConstraint SameAAndBAs(this ConstraintExpression expression, A expected) { var constraint = new SameAAndBConstraint(expected); expression.Append(constraint); return constraint; } }
3. 编写测试用例
使用简洁语法编写测试,失败时会输出明确的属性对比信息:
[TestFixture] public class ATests { [Test] public void When_InstancesHaveDifferentPropertyB_ShouldFail() { var a1 = new A("wordA", "wordB"); var a2 = new A("wordA", "wordC"); Assert.That(a1, Has.SameAAndBAs(a2)); } [Test] public void When_PropertiesContainCommas_ShouldDistinguish() { var a1 = new A("wordA, wordB", "wordC"); var a2 = new A("wordA", "wordB, wordC"); Assert.That(a1, Has.SameAAndBAs(a2)); } }
失败消息示例
当第二个测试失败时,NUnit会输出:
Expected: instance of A with PropertyA='wordA', PropertyB='wordB, wordC'
But was: instance of A with PropertyA='wordA, wordB', PropertyB='wordC'
清晰展示两个实例的关键属性值,完全避免了ToString的歧义问题。
补充说明
- 原类A的
ToString方法存在笔误,应使用PropertyA和PropertyB而非Property1/Property2,建议修正。 - 自定义约束的优势在于完全控制验证逻辑和错误提示,不受类自身
ToString实现的限制,适合需要精准对比的场景。
内容的提问来源于stack exchange,提问作者suitendaal
相关产品推荐
相关产品推荐

