如何模拟Web服务

我是否必须重写我的代码才能在界面中执行此操作? 或者有更简单的方法吗? 我正在使用Moq

我通常做的是围绕我的Web服务构建一个包装器或适配器,然后嘲笑它。

例如:

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

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

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

最近一直在写关于unit testing和嘲笑的几个回复。 我在其他地方写过,问问自己究竟在测试什么很重要的。 关于你的具体情况,我希望答案是“我正在测试我的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 (); } } 

在prod

 // 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服务的业务组件,我同意您不希望为unit testing创​​建客户端。

 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 } 

通常,如果类的依赖项是进程内服务,那么应用dependency injection[DI]或控制反转[IoC]等模式的决定取决于您 – 并且您希望隔离和unit testing这些服务将通知您设计。 但是,如果一个类的依赖项跨越一个进程边界 ,例如Database或WebService,我强烈建议像我们上面那样应用这些模式。

真的,这只是简单的旧界面开发。 你可能已经看到它是如何得到回报的。

🙂

很久以前我在博客上写过这篇文章 。 基本上使用部分类和一些努力(自动或手动,取决于您将更改Web服务的频率),您可以使Web服务代理类实现一个接口。 然后你可以正常模拟它。

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

 public partial class DbService:IService { } 

留空类,因为Web服务是部分类我们使用这个实现。 (先前