8

下面using点击了一个我不想实际点击的外部资源。我想测试someResult和使用它的代码,但是每次我运行单元测试时,这段代码仍然会尝试访问真正的 Web 服务。如何使用最小起订量来伪造对 Web 服务的真实调用,但不模拟使用中的其余代码?

public IMyInterface.SomeMethod()
{    
     // hits a web service
     using ( mySoapClient client = new mySoapClient() )
     {
          var someResult = client.DoSomething();
       ...
       ...
     }
}


[TestMethod()]
public void SomeMethodTest()
{
    IMyInterface target = new MyInterface();
    target.SomeMethod();

    // Assert....
}
4

3 回答 3

14

您需要将 Web 服务实现与使用者分离

public class ClassIWantToTest
{
      public ClassIWantToTest(IServiceIWantToCall service) {}

      public void SomeMethod()
      {
           var results = service.DoSomething();
           //Rest of the logic here
      }
}

现在您可以使用 Moq 来模拟IServiceIWantToCall以测试逻辑SomeMethod

于 2012-08-30T19:46:37.927 回答
2

为了增加泡菜的答案,我interface为我当前的服务调用创建了一个名为IService. 然后我创建了一个ServiceMock继承接口的类并添加了一个名为_service. 在构造函数中,我实例化模拟服务并设置接口的所有方法,如下所示:

public class ServiceMock : IService
{
    Mock<IService> _serviceMock;

    public ServiceMock()
    {
        _serviceMock = new Mock<IService>();

        _serviceMock.Setup(x => x.GetString()).Returns("Default String");

        SomeClass someClass = new SomeClass();
        someClass.Property1= "Default";
        someClass.Property2= Guid.NewGuid().ToString();

        _serviceMock.Setup(x => x.GetSomeClass()).Returns(someClass);
    }

    public string GetString()
    {
        return _serviceMock.Object.GetString();
    }

    public License GetSomeClass()
    {
        return _serviceMock.Object.GetSomeClass();
    }
}

然后,您将此类注入到您的代码中,而不是实际的 Web 服务中。它将返回您设置为返回的值。您现在可以在不依赖 Web 服务的情况下进行测试。

于 2014-03-31T19:23:46.717 回答
1

您首先必须能够注入 Web 服务。在 SomeMethod() 中创建一个新方法将方法“紧密耦合”到生产代码;您不能动态地告诉它创建除 mySoapClient 之外的其他内容。

由于您要创建和销毁它们,我是否建议您要测试的代码接受 aFunc<IMySoapClient>作为方法参数或构造函数参数。它看起来像这样:

public IMyInterface.SomeMethod(Func<IMySoapClient> clientFactory)
{    
     // hits a web service
     using ( mySoapClient client = clientFactory() )
     {
          var someResult = client.DoSomething();
       ...
       ...
     }
}

... 或者:

public class MyClass:IMyInterface
{
   private Func<IMySoapClient> MySoapClientFactoryMethod;

   public MyClass(Func<IMySoapClient> clientFactoryMethod)
   {
      MySoapClientFactoryMethod = clientFactoryMethod;
   }

   ...

   public IMyInterface.SomeMethod()
   {    
        // hits a web service
        using ( mySoapClient client = MySoapClientFactoryMethod() )
        {
             var someResult = client.DoSomething();
          ...
          ...
        }
   }
}

现在,当您创建要测试的对象时,您定义了一个生成 Soap 服务的适当 Moq 模拟的函数,该函数具有您期望从真实客户端获得的行为而没有副作用(包括能够告诉客户端的代码 Dispose()d),并将该函数传递给您正在测试的类或方法。在生产中,你可以简单地将函数定义为()=>new mySoapClient(),或者你可以建立一个 IoC 框架并将 mySoapClient 注册为 IMySoapClient,然后也注册 MyClass;大多数 IoC 框架都足够聪明,可以将委托视为参数并生成注入注册依赖项的方法。

于 2012-08-30T19:52:22.753 回答