C#/.net 单元测试xUnit、Mock、Moq
在做单元测试的时候,有时需要引用很多的外部对象,例如网络通信、记录日志等。单元测试无法控制这些外部的依赖对象,所以需要使用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@", "文件名符合要求"); } } }
我们发现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@", mockService.Email); Assert.Equal("文件名符合要求", mockService.message); }
stub和Mock的区别
从上面可以看出,Stub是完全模拟一个外部依赖(直接输出,无法进行断言),而Mock则是用来断言
注意事项:
要以接口为依赖对象,例如本案例中
public IWebService webService { get; set; } public IEmailService emailService { get; set; }
Moq是.net平台下的一个非常流行的模拟库,目前依赖注入模式非常流行,有时被测试的类或者方法需要注入数十项接口,如果像上面那样将接口重写为自定义的“假实现”,也要写大量的代码,而利用moq框架可以自动生成接口的代理对象,减少工作量。