在做单元测试的时候,有时需要引用很多的外部对象,例如网络通信、记录日志等。单元测试无法控制这些外部的依赖对象,所以需要使用Stub和Mock来模拟这些外部对象。
用以下实例来进行单元测试
//检查文件名的长度,并使用IWebService来记录错误
public class CheckLength
{
public IWebService webService { get; set; }
public IEmailService emailService { get; set; }
public void Analyze(string fileName)
{
if (fileName.Length<8)
{
webService.LogError("文件名称太短");
}
else
{
emailService.SendEmail("123@qq.com", "文件名符合要求");
}
}
}
我们发现webService和emailService都是外部依赖对象,需要我们自己写Stub和Mock来模拟这两个外部对象
public class StubWebService : IWebService
{
public void LogError(string message)
{
Debug.WriteLine(message);
}
}
public class MockEmailService : IEmailService
{
public string Email { get; set; }
public string message { get; set; }
public void SendEmail(string email, string message)
{
this.Email= email;
this.message = message;
}
}
然后进行单元测试
[Fact()]
public void AnalyzeTest()
{
//arange
StubWebService stubService = new StubWebService();
MockEmailService mockService = new MockEmailService();
CheckLength checkLength = new CheckLength();
//将自定义的服务赋给checkLength
checkLength.emailService = mockService;
checkLength.webService= stubService;
//act
string fileName = "a3t";
checkLength.Analyze(fileName);
//assert
Assert.Equal("123@qq.com", mockService.Email);
Assert.Equal("文件名符合要求", mockService.message);
}
从上面可以看出,Stub是完全模拟一个外部依赖(直接输出,无法进行断言),而Mock则是用来断言
注意事项:
要以接口为依赖对象,例如本案例中
public IWebService webService { get; set; }
public IEmailService emailService { get; set; }
Moq是.net平台下的一个非常流行的模拟库,目前依赖注入模式非常流行,有时被测试的类或者方法需要注入数十项接口,如果像上面那样将接口重写为自定义的“假实现”,也要写大量的代码,而利用moq框架可以自动生成接口的代理对象,减少工作量。