我有一个使用Web服务的类,大致如下:
public class MyService : IMyService
{
private readonly IAuxilaryService1 auxilaryService1;
private readonly IAuxilaryService2 auxilaryService2;
private readonly IAuxilaryService3 auxilaryService3;
private IWebService service;
public MyService()
{
auxilaryService1 = new AuxilaryService1();
auxilaryService2 = new AuxilaryService2();
auxilaryService3 = new AuxilaryService3();
}
public void DoSomething(
string Param1,
string Param2
)
{
service = new WebService(auxilaryService1, auxilaryService2, auxilaryService3);
var response = service.DoSomething(Param1, Param2);
/* ... */
}
然后进行单元测试试图测试这个:
私人模拟webService;
[SetUp]
public void SetUp()
{
webService = new Mock<IWebService>();
}
[Test]
public void MyService_DoSomethingTest()
{
IMyService myService = new MyService();
webService.Setup(x => x.DoSomething(It.IsAny<string>(), It.IsAny<string>()))
.Returns(new Response() { Status = "Foo"});
myService.DoSomething("Param1", "Param2");
webService.Verify(x => x.DoSomething(It.IsAny<string>(), It.IsAny<string>()));
}
首先,这是一个测试“MyService”的好方法,其次,由于某些原因,在我的测试中没有正确拦截接口,即使我确实要求myService中的webService返回一个假响应,实际的实例仍然被调用,测试失败并带有Soap异常。我知道Moq需要接口或虚拟方法,但我提供了一个接口Mock,为什么它不能拦截呢?有任何想法吗?
我需要补充一点,我正在测试自定义的umbraco轮廓工作流类型,我无法控制构造函数。如果我改变它,项目就会破裂。
答案 0 :(得分:2)
为了测试你的类,你应该将模拟的依赖项传递给被测试的类。在您的情况下,所有依赖项都在MyService
中进行了硬编码(它们在类中实例化)。使用依赖注入来提供依赖关系:
public class MyService : IMyService
{
private readonly IAuxilaryService1 auxilaryService1;
private readonly IAuxilaryService2 auxilaryService2;
private readonly IAuxilaryService3 auxilaryService3;
private IWebService service;
// constructor injection
public MyService(IAuxilaryService1 service1,
IAuxilaryService2 service2,
IAuxilaryService3 service3)
{
auxilaryService1 = service1;
auxilaryService2 = service2;
auxilaryService3 = service3;
}
// pass IWebService into method
public void DoSomething(string Param1, string Param2, IWebService service)
{
this.service = service;
var response = service.DoSomething(Param1, Param2);
/* ... */
}
}
现在测试应该如何:
private IMyService myService;
[SetUp]
public void SetUp()
{
IAuxilaryService1 service1 = new Mock<IAuxilaryService1>();
IAuxilaryService2 service2 = new Mock<IAuxilaryService2>();
IAuxilaryService3 service3 = new Mock<IAuxilaryService3>();
myService = new MyService(service1.Object,
service2.Object,
service3.Object);
}
[Test]
public void MyService_DoSomethingTest()
{
// Arrange
webService = new Mock<IWebService>();
webService.Setup(x => x.DoSomething(It.IsAny<string>(), It.IsAny<string>()))
.Returns(new Response() { Status = "Foo"});
// Act
myService.DoSomething("Param1", "Param2", webService.Object);
// Assert
webService.Verify(x => x.DoSomething(It.IsAny<string>(),It.IsAny<string>()));
}
BTW奇怪的是,你在DoSomething
方法中实例化webService并将webService分配给class字段。也许您需要通过构造函数将webService传递到您的类中?
答案 1 :(得分:2)
您永远不会将模拟的实例注入myService
。您可以创建一个构造函数来注入依赖项。像这样的东西
public MyService(IWebService service)
{
this.service = service;
}
然后你必须在测试中使用这个构造函数。
答案 2 :(得分:2)
由于以下行,实现不使用模拟实例:
service = new WebService(auxilaryService1, auxilaryService2, auxilaryService3);
欢迎使用依赖注入。如果你想模仿这个对象,MyService
需要要求它而不是它。
让你的代码看起来像这样:
private readonly IWebService webService;
public MyService(IWebService webService)
{
this.webService = webService;
}
public void DoSomething(...)
{
var response = webService.DoSomething(Param1, Param2);
/* ... */
}
在测试中,您需要将模拟实例传递给构造函数:
IMyService myService = new MyService(webService);