如何在NUnit中断言集合存在符合自定义条件的元素?
解决方案
1. 单个元素的优雅断言写法
针对单个输入元素的场景,你可以直接使用NUnit的Has.Some.Matches约束,直接对结果集合断言,无需额外转换:
[Test] public void SinglePersonConversionTest() { var inputPerson = GenerateOtherPerson(); List<Person> result = _classUnderTest.ConverToPerson(new[] { inputPerson }.ToList()); // 直接对结果集合断言,验证存在匹配的元素 Assert.That(result, Has.Some.Matches<Person>(p => AreEquivalent(p, inputPerson))); } public bool AreEquivalent(Person p1, OtherPerson p2) { return p1.Name == $"{p2.FirstName} {p2.LastName}" && p1.Age == DateTime.Now.Year - p2.DateOfBirth.Year && p1.Uuid == p2.Guid.ToString(); }
2. 多个元素的场景:验证每个输入都有对应匹配
如果是多输入元素的场景,要确保每个输入的OtherPerson都能在结果中找到等价的Person,可以用以下两种方式:
方式一:循环验证每个输入的匹配存在
这种方式直观清晰,适合需要明确每个输入都对应结果的场景:
[Test] public void MultiplePersonsConversionTest() { var inputPersons = new List<OtherPerson> { GenerateOtherPerson(), GenerateOtherPerson(), GenerateOtherPerson() }; List<Person> result = _classUnderTest.ConverToPerson(inputPersons); // 对每个输入元素,验证结果中存在匹配项 foreach (var input in inputPersons) { Assert.That(result, Has.Some.Matches<Person>(p => AreEquivalent(p, input))); } }
方式二:双向验证确保一一对应
如果需要同时验证结果集合没有多余元素(输入和结果完全一一匹配),可以补充双向断言:
[Test] public void ExactMatchConversionTest() { var inputPersons = new List<OtherPerson> { GenerateOtherPerson(), GenerateOtherPerson() }; List<Person> result = _classUnderTest.ConverToPerson(inputPersons); // 先验证数量一致 Assert.That(result.Count, Is.EqualTo(inputPersons.Count)); // 验证每个输入都有对应结果,且每个结果都对应一个输入 Assert.That(inputPersons, All.Matches<OtherPerson>(input => result.Any(p => AreEquivalent(p, input)))); Assert.That(result, All.Matches<Person>(p => inputPersons.Any(input => AreEquivalent(p, input)))); }
3. 进阶:自定义NUnit约束简化断言
如果这类等价性验证频繁出现,可以自定义NUnit约束,让断言更简洁:
public class EquivalentToOtherPersonConstraint : Constraint { private readonly OtherPerson _expected; public EquivalentToOtherPersonConstraint(OtherPerson expected) { _expected = expected; } public override ConstraintResult ApplyTo<TActual>(TActual actual) { if (actual is not Person person) return new ConstraintResult(this, actual, ConstraintStatus.Failure); bool isEquivalent = person.Name == $"{_expected.FirstName} {_expected.LastName}" && person.Age == DateTime.Now.Year - _expected.DateOfBirth.Year && person.Uuid == _expected.Guid.ToString(); return new ConstraintResult(this, actual, isEquivalent ? ConstraintStatus.Success : ConstraintStatus.Failure); } } // 扩展方法简化调用 public static class ConstraintExtensions { public static EquivalentToOtherPersonConstraint EquivalentTo(this ConstraintExpression expression, OtherPerson expected) { var constraint = new EquivalentToOtherPersonConstraint(expected); expression.Append(constraint); return constraint; } }
之后断言可以写成非常简洁的形式:
Assert.That(result, Has.Some.EquivalentTo(inputPerson));
内容的提问来源于stack exchange,提问作者ewok
相关产品推荐
相关产品推荐

