【发布时间】:2009-10-23 18:14:36
【问题描述】:
我是否必须重写我的代码才能在接口中执行此操作?或者有没有更简单的方法?我正在使用起订量
【问题讨论】:
标签: c# .net web-services moq mocking
我是否必须重写我的代码才能在接口中执行此操作?或者有没有更简单的方法?我正在使用起订量
【问题讨论】:
标签: c# .net web-services moq mocking
我通常做的是围绕我的网络服务构建一个包装器或适配器,然后模拟它。
例如:
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
}
【讨论】:
最近一直在写一些关于单元测试和模拟的回复。我在其他地方写道,问自己究竟在测试什么很重要。关于您的具体情况,我希望答案是“我正在测试我的 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,我强烈建议像我们上面那样应用这些模式。
真的,这只是普通的旧界面开发。您可能已经看到它的回报了。
:)
【讨论】:
我很久以前blogged about this。基本上使用部分类和一些努力(自动或手动,取决于您更改 Web 服务的频率),您可以使 Web 服务代理类实现一个接口。然后,您可以正常模拟它。
【讨论】:
有一个简单的方法。 例如,如果我们有名为 DbService 的 WebService 类, 首先为其创建一个接口(例如 IService),并使用此接口进行模拟,然后将一个类添加到您的项目中并放入:
public partial class DbService:IService {
}
将类留空,因为 Web 服务是部分类,我们使用此实现。 (以前
【讨论】: