我建议让 SaveIt 返回一个成功或失败的结果,这只是让整体测试更容易。你可以做一些简单的事情,比如让它返回一个布尔值,或者如果你需要报告它是通过还是失败,你也可以创建一个通用的结果类,它还包含设置消息的能力。
一个简单的例子
public class Result
{
public bool IsSuccess;
public List<string> Messages;
}
在单元测试中,您尝试仅测试 OnSomething 行为——不应测试“SaveIt”内部发生的情况。因此,理想情况下,您希望 SaveIt() 出现在另一个类中,这样您就可以模拟它的响应。
我为此使用最小起订量。起订量免费,您可以在这里获取:http://code.google.com/p/moq/
我的方法会变成
Result OnSomething()
{
Result result=null;
increment++;
if(increment == 20)
{
result = saver.SaveIt();
}
return result;
}
您的类构造函数将采用实现 ISaver 接口的对象(定义 SaveIt() 方法)(理想情况下由 DI 框架注入,但如果需要,您可以手动生成它)。
现在在您的单元测试中,您将创建一个模拟版本的 ISaver,并告诉它在被调用时返回什么:
Mock<ISaver> mock = new Mock<ISaver>();
mock.Setup(x=> x.SaveIt()).Returns(new Result{IsSuccess=true});
您将在构造函数 ISaver 参数中通过 mock.Object 实例化您的类。
例如
MyClass myClass = new MyClass(mock.Object);
//(assuming it didn't have other parameters)
然后,您可以断言 result 是否为 null ——如果它从未被调用,它将为 null,因为您在上面所做的设置永远不会触发。
(in nunit)
Result result = myClass.OnSomething();
Assert.IsNotNull(result);
如果您真的不希望 OnSomething() 返回结果,或者因为它是一个事件而不能返回结果,那么我会让 OnSomething() 调用一个方法来为您完成工作:
void OnSomething()
{
Result result = DoTheWork();
}
Result DoTheWork()
{
Result result=null;
increment++;
if(increment == 20)
{
result = saver.SaveIt();
}
return result;
}
然后在 DoTheWork() 而不是 OnSomething() 上运行您的单元测试。