我是否必须重写我的代码才能在界面中执行此操作?或者有更简单的方法吗?我正在使用Moq
答案 0 :(得分:39)
我通常做的是围绕我的Web服务构建一个包装器或适配器,然后嘲笑它。
例如:
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
}
答案 1 :(得分:34)
最近写了一些关于单元测试和嘲笑的回复。我在其他地方写过,问问自己你正在测试的究竟是很重要的。关于你的具体情况,我希望答案是“我正在测试我的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 ();
}
}
in 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服务,我同意您不想为单元测试创建客户端。
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,我强烈建议像上面那样应用这些模式。
真的,这只是简单的旧界面开发。你可能已经看到它是如何得到回报的。
:)
答案 2 :(得分:10)
答案 3 :(得分:2)
有一种简单的方法。 例如,如果我们的WebService类名为DbService, 首先为它创建一个接口(例如IService),然后使用这个接口进行模拟,然后在项目中添加一个类并放入:
public partial class DbService:IService {
}
将类留空,因为Web服务是部分类我们使用此实现。 (以前