我正在开发一个新的MVC 5应用程序。我的项目中有一个Integration Layer,我有一个外部Web服务的服务引用。
然后我创建了一个有一些方法的接口 - 然后我有一个服务类,如下所示:
public class MyService : IMyService
{
private readonly ExternalServiceClient _serviceClient;
public MyService()
{
_serviceClient = new ExternalServiceClient ("WSHttpBinding_IMyService");
}
public string GetName(Coordinate[] coordinates)
{
string name = string.Empty;
name = _serviceClient.GetInformationsForCoordinates(coordinates);
return name;
}
请注意,这将被删除,实际上会添加带有异常处理的try catch块等
我有一个Integration.Tests项目,用于集成层的单元测试。测试GetName方法的最佳实践方法是什么?我是否应该在测试项目中向服务的端点添加另一个服务引用,或者如果我们使用Moq,我可以创建一个实际服务的实例,例如Web层将调用它 - 以及如何完成?
答案 0 :(得分:8)
您的情况的最佳做法取决于您的架构设计。
您的服务显然取决于ExternalServiceClient
,并且您在MyService
类内部对其进行了实例化,这不允许您轻松切换依赖关系,从而导致您头痛是时候测试一下了。
真正的问题应该是:
我如何设计我的服务以使其易于测试?
因为你可以模仿MyService
依赖,你将能够彻底测试它,并能够通过红绿重构证明你的服务完美无瑕。
以我的拙见,你的班级应该这样:
public class MyService : IMyService {
public MyService(ExternalServiceClient serviceClient) {
externalServiceClient = serviceclient;
}
public string GetName(Coordinate[] coordinates) {
string name = string.Empty;
name = externalServiceClient.GetInformationForCoordinates(coordinates);
return name;
}
private readonly ExternalServiceClient externalServiceclient;
}
这样,您就可以随意替换您的依赖项,从而使用模拟。
使用NUnit
和 Moq
,您可以按如下方式测试您的服务:
[TestFixture]
public class MyServiceTests {
[TestFixture]
public class GetCoordinates : MyServiceTests {
// Given
string expected = "Name";
Coordinate[] coordinates = new Coordinate[] { ... }
externalServiceClient.Setup(esc => esc.GetInformationForCoordinates(coordinates)).Returns(expected);
// When
string actual = myService.GetName(coordinates);
// Then
externalServiceClientMock.Verify(esc => esc.GetInformationCoordinates(coordinates));
Assert.AreEqual(expected, actual);
}
[SetUp]
public void MyServiceSetup() {
externalServiceClient = new Mock<ExternalServiceClient>("WSHttpBinding_IMyService");
myService = new MyService(externalServiceClientMock.Object);
}
private Mock<ExternalServiceClient> externalServiceClientMock;
private MyService myService;
}
答案 1 :(得分:1)
一般情况下,将参数化构造函数注入对象构造的依赖性是一种很好的做法(因为ExternalServiceClient
具有只读语义)。然后你可以在你的测试用例中注入mock。
在您的情况下,如果存在在ExternalServiceClient
private readonly ExternalServiceClient _serviceClient;
public MyService(IExternalServiceClient serviceClient)
{
_serviceClient = serviceClient;
}
然后将其用作:
var service = new MyService(new ExternalServiceClient ("WSHttpBinding_IMyService"));
并在测试中
IExternalServiceClient mockObject = //construct mock with desired behabiour then pass to ctor
var service = new MyService(mockObject);
如果没有实现的接口和添加它的能力(因为它是外部的),你必须做一些虚拟的技巧。