【问题标题】:How to mock a web service如何模拟 Web 服务
【发布时间】:2009-10-23 18:14:36
【问题描述】:

我是否必须重写我的代码才能在接口中执行此操作?或者有没有更简单的方法?我正在使用起订量

【问题讨论】:

    标签: c# .net web-services moq mocking


    【解决方案1】:

    我通常做的是围绕我的网络服务构建一个包装器或适配器,然后模拟它。

    例如:

    public class ServiceAdapter: IServiceAdapter
    {
        public void CallSomeWebMethod()
        {
            var someService = new MyWebService();
            someService.SomeWebMethod();
        }
    }
    

    然后我只存根服务适配器。

    [Test]    
    public void SomeMethod_Scenario_ExpectedResult()
    {
        var adapterMock = new Mock<IServiceAdapter>();
        //do your test
    }
    

    【讨论】:

      【解决方案2】:

      最近一直在写一些关于单元测试和模拟的回复。我在其他地方写道,问自己究竟在测试什么很重要。关于您的具体情况,我希望答案是“我正在测试我的 WebService 所公开的业务逻辑”,而不是“我正在测试我的 WebService”——这是有区别的。


      如果您的问题是服务器端

      您通常不需要测试 WebServices。 MS 已经这样做了。数百万人已经这样做了。测试传输层、协议、WebServices的定义都是浪费时间。

      您需要针对您的业务逻辑。最好的方法是将您的业务逻辑与您的 WebService分离。考虑以下

      public class MyWebSevice : System.Web.Services.WebService
      {
          private AuthenticationService _auth = new AuthenticationService ();
          private int _count = 0;
          [WebMethod]
          public string DoSomething ()
          {
              // embedded business logic, bad bad bad
              if (_auth.Authenticate ())
              {
                  _count++;
              }
              return count.ToString ();
          }
      }
      

      如果不直接调用 WebService,就无法测试该逻辑。你真正想要的是

      public class MyService 
      {
          // keeners will realise this too should be injected
          // as a dependency, but just cut and pasted to demonstrate
          // isolation
          private AuthenticationService _auth = new AuthenticationService ();
          private int _count = 0;
          public string DoSomething ()
          {
              if (_auth.Authenticate ())
              {
                  _count++;
              }
              return count.ToString ();
          }
      }
      

      在生产中

      // this web service is now a consumer of a business class,
      // no embedded logic, so does not require direct testing
      public class MyWebSevice : System.Web.Services.WebService
      {
          private readonly MyService _service = new MyService ();
      
          [WebMethod]
          public string DoSomething ()
          {
              _service.DoSomething ();
          }
      }
      

      测试中

      // test business logic without web service! yay!
      [Test]
      public void Test_DoSomething ()
      {
          MyService service = new MyService ();
          string actual = service.DoSomething ();
          // verify results
      }
      

      管理依赖项 [如 AuthenticationService 成员] 是一个单独的问题。但是,让您的 WebMethods 简单的传递到适当的底层业务类并从它们中完全删除逻辑,允许您针对“真实”用户代码,而不是典型 WebService 实现的管道。


      如果您的问题是客户端

      您有一个业务组件调用 Web 服务,我同意您不想为单元测试创​​建客户端。

      public partial class MyWebService :
          System.Web.Services.Protocols.SoapHttpClientProtocol 
      {
          ...
          public string DoSomething () { ... }
      }
      
      public class MyClient
      {
          public void CallService ()
          {
              MyWebService client = new MyWebService ();
              client.DoSomething ();
          }
      }
      

      在这里,您有依赖问题,即您无法在没有实例化和托管 WebService 的情况下测试 MyClient.CallService。如果您不拥有或托管所述远程服务,尤其令人不安。在这种情况下,是的,您应该针对接口编写 - 再次分离和隔离业务逻辑。

      public interface IMyWebService
      {
          string DoSomething ();
      }
      
      public class MyWebServiceWrapper : IMyWebService
      {
          public string DoSomething () 
          {
              MyWebService client = new MyWebService ();
              client.DoSomething ();
          }
      }
      
      public class MyClient
      {
          private readonly IMyWebService _client = null;
          public MyClient () : this (new MyWebServiceWrapper ()) { }
          public MyClient (IMyWebService client)
          {
              _client = client;
          }
          public void CallService ()
          {
              _client.DoSomething ();
          }
      }
      

      测试中

      [Test]
      public void Test_CallService ()
      {
          IMyWebService mockService = null;
          // instantiate mock with expectations
          MyClient client = new MyClient (mockService);
          client.CallService ();
          // verify results
      }
      

      一般来说,如果一个类的依赖项是进程内服务,那么应用依赖注入 [DI] 或控制反转 [IoC] 等模式的决定取决于您 - 以及您对这些服务进行隔离和单元测试的愿望将通知您的设计。但是,如果一个类的依赖项跨越进程边界,例如数据库或 WebService,我强烈建议像我们上面那样应用这些模式。

      真的,这只是普通的旧界面开发。您可能已经看到它的回报了。

      :)

      【讨论】:

      • arg,我认为@Joseph 击败了我——虽然更冗长,但我提出了同样的建议:P
      【解决方案3】:

      我很久以前blogged about this。基本上使用部分类和一些努力(自动或手动,取决于您更改 Web 服务的频率),您可以使 Web 服务代理类实现一个接口。然后,您可以正常模拟它。

      【讨论】:

        【解决方案4】:

        有一个简单的方法。 例如,如果我们有名为 DbService 的 WebService 类, 首先为其创建一个接口(例如 IService),并使用此接口进行模拟,然后将一个类添加到您的项目中并放入:

        public partial class DbService:IService {
        
        }
        

        将类留空,因为 Web 服务是部分类,我们使用此实现。 (以前

        【讨论】:

          猜你喜欢
          • 2010-10-11
          • 2018-04-30
          • 1970-01-01
          • 2012-10-27
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2018-06-21
          • 1970-01-01
          相关资源
          最近更新 更多