另一种选择是通过实现NUnit抽象的Constraint
类编写自定义约束条件。使用帮助类提供一些语法糖,生成的测试代码简洁易读。
Assert.That( LeftObject, PortfolioState.Matches( RightObject ) )
举个极端的例子,考虑一个类,它有“只读”成员,不是IEquatable
,即使你想改变被测试的类,也不能:
public class Portfolio
{
private Portfolio(){ }
public string Property1 { get; private set; }
public string Property2 { get; private set; }
public string Property3 { get; private set; }
public static Portfolio GetPortfolio(string p1, string p2, string p3)
{
return new Portfolio()
{
Property1 = p1,
Property2 = p2,
Property3 = p3
};
}
public static Portfolio GetDefault()
{
return new Portfolio()
{
Property1 = "{{NONE}}",
Property2 = "{{NONE}}",
Property3 = "{{NONE}}"
};
}
}
Constraint
类的合同要求必须重写Matches
和WriteDescriptionTo
方法(在不匹配的情况下,提供预期值的叙述),但是重写WriteActualValueTo
方法(提供实际值的叙述)也是有意义的:
public class PortfolioEqualityConstraint : Constraint
{
Portfolio expected;
string expectedMessage = "";
string actualMessage = "";
public PortfolioEqualityConstraint(Portfolio expected)
{
this.expected = expected;
}
public override bool Matches(object actual)
{
if ( actual == null && expected == null ) return true;
if ( !(actual is Portfolio) )
{
expectedMessage = "<Portfolio>";
actualMessage = "null";
return false;
}
return Matches((Portfolio)actual);
}
private bool Matches(Portfolio actual)
{
if ( expected == null && actual != null )
{
expectedMessage = "null";
expectedMessage = "non-null";
return false;
}
if ( ReferenceEquals(expected, actual) ) return true;
if ( !( expected.Property1.Equals(actual.Property1)
&& expected.Property2.Equals(actual.Property2)
&& expected.Property3.Equals(actual.Property3) ) )
{
expectedMessage = expected.ToStringForTest();
actualMessage = actual.ToStringForTest();
return false;
}
return true;
}
public override void WriteDescriptionTo(MessageWriter writer)
{
writer.WriteExpectedValue(expectedMessage);
}
public override void WriteActualValueTo(MessageWriter writer)
{
writer.WriteExpectedValue(actualMessage);
}
}
再加上辅助类:
public static class PortfolioState
{
public static PortfolioEqualityConstraint Matches(Portfolio expected)
{
return new PortfolioEqualityConstraint(expected);
}
public static string ToStringForTest(this Portfolio source)
{
return String.Format("Property1 = {0}, Property2 = {1}, Property3 = {2}.",
source.Property1, source.Property2, source.Property3 );
}
}
示例用法:
[TestFixture]
class PortfolioTests
{
[Test]
public void TestPortfolioEquality()
{
Portfolio LeftObject
= Portfolio.GetDefault();
Portfolio RightObject
= Portfolio.GetPortfolio("{{GNOME}}", "{{NONE}}", "{{NONE}}");
Assert.That( LeftObject, PortfolioState.Matches( RightObject ) );
}
}