使用以下代码:
class Client {
private Service _service;
public Client() {
_service = new Service; // Connection is made to endpoint
}
public string GetData() {
return _service.ReadData();
}
}
如何在不修改构造函数或访问修饰符的情况下使用Moq来模拟服务?
答案 0 :(得分:3)
为了实现这一目标(或至少,干净利落),您必须执行依赖注入。您的类不应该实例化服务。它应该接收已经实例化的服务实例。
class Client {
private Service _service;
public Client(Service service) {
_service = service; // maybe you check for null or other checks here
}
public string GetData() {
return _service.ReadData();
}
}
下一步:您应该将您的类设置为依赖于接口 IService而不是实际的Service类。这样,您可以轻松创建另一个可以在实例化类时注入而不是服务的ServiceMock。
class Client {
private IService _service;
public Client(IService service) {
_service = service; // maybe you check for null or other checks here
}
public string GetData() {
return _service.ReadData();
}
}
与您的要求相关:
不修改构造函数或访问修饰符?
这不是一个好习惯,它可能变得很脏。我没有这样的解决方案,因为你使用直接类型而不是接口。
我不知道你是在处理一些遗留代码还是第三方库,但是通过编程接口而不是类来预测这类问题是关键。
答案 1 :(得分:1)
再次强调这一点:
new Service()
构造函数正在连接到端点,则您将无法模拟此代码。即使您之后更换了实例,UnitTests也不应该依赖于另一个可用的端点。Service
未提供可模拟的接口IService
且其方法不是虚拟的,则根本无法模拟它。您需要创建一个包装器接口和实现一个常见的解决方法是创建一个具有受限可见性(例如内部)的第二个构造函数,并使用它将模拟注入到您的类中。您可以使用InternalsVisibleTo
属性控制可见性。有一些关于为测试创建构造函数的讨论,但这是朝着正确方向迈出的第一步。
class Client {
private Service _service;
// Only for UnitTests
internal Client(Service service) {
_Service = service
}
public Client() {
_service = new Service(); // Connection is made to endpoint
}
public string GetData() {
return _service.ReadData();
}
}
将所有评论中的内容整合到一个可用的示例中:
class Client {
private IService _service;
Client(IService service) {
_service = service;
}
public string GetData() {
return _service.ReadData();
}
}
class ClientFactory {
public Client CreateClient(){
var service = new Service(); // Connection is made to endpoint
return new Client(service);
}
}