-1

我有一个类使用大致如下所示的 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);
        /* ... */
    }

然后一个单元测试试图测试这样做:

私人模拟网络服务;

    [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 轮廓工作流类型,并且我无法控制构造函数。如果我改变它,项目就会中断。

4

3 回答 3

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>()));
}

顺便说一句,您在方法内部实例化 webServiceDoSomething并将 webService 分配给类字段,这很奇怪。也许您还需要通过构造函数将 webService 传递给您的类?

于 2013-03-26T12:20:27.997 回答
2

您永远不会将模拟实例注入到myService. 您可以创建一个构造函数来注入依赖项。像这样的东西

  public MyService(IWebService service)
  {
      this.service = service;
  }

然后你必须在你的测试中使用这个构造函数。

于 2013-03-26T12:22:15.317 回答
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);
于 2013-03-26T12:24:38.777 回答