Moq - 如何模拟Web服务调用?

时间:2012-08-30 19:42:30

标签: c# unit-testing moq

下面的using会点击我不想实际点击的外部资源。我想测试someResult以及使用它的代码,但每次运行单元测试时,此代码仍会尝试访问真正的Web服务。如何使用moq伪造对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....
}

3 个答案:

答案 0 :(得分:13)

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

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

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

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

答案 1 :(得分:2)

要添加到pickles的答案,我为名为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服务的情况下进行测试。

答案 2 :(得分:1)

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

由于您要创建和销毁它们,我可以建议您要测试的代码接受Func<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框架足够聪明,可以将委托视为参数,并生成注入已注册依赖项的方法。