C# 模拟类中定义的对象
使用以下代码:C# 模拟类中定义的对象,c#,unit-testing,moq,C#,Unit Testing,Moq,使用以下代码: class Client { private Service _service; public Client() { _service = new Service; // Connection is made to endpoint } public string GetData() { return _service.ReadData(); } } 在不修改构造函数或访问修饰符的情况下,如何使用Moq
class Client {
private Service _service;
public Client() {
_service = new Service; // Connection is made to endpoint
}
public string GetData() {
return _service.ReadData();
}
}
在不修改构造函数或访问修饰符的情况下,如何使用Moq模拟服务?要做到这一点(或至少是干净地做到这一点),您必须进行依赖项注入。您的类不应实例化该服务。它应该接收一个已经实例化的服务实例
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();
}
}
下一步:您应该将类设置为依赖接口而不是实际的服务类。通过这种方式,您可以轻松创建另一个ServiceMock,当您实例化类时,该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();
}
}
与您的要求相关: 不修改构造函数或访问修饰符 这不是一个好的做法,它可能会变得非常肮脏。我没有这样的解决方案,因为您使用的是直接类型而不是接口 我不知道您是否正在处理一些遗留代码或第三方库,但通过编程到接口而不是类来解决这类问题是这里的关键。要做到这一点(或者至少是干净地做到这一点),您必须进行依赖项注入。您的类不应实例化该服务。它应该接收一个已经实例化的服务实例
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();
}
}
下一步:您应该将类设置为依赖接口而不是实际的服务类。通过这种方式,您可以轻松创建另一个ServiceMock,当您实例化类时,该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();
}
}
与您的要求相关: 不修改构造函数或访问修饰符 这不是一个好的做法,它可能会变得非常肮脏。我没有这样的解决方案,因为您使用的是直接类型而不是接口
我不知道您是否正在处理一些遗留代码或第三方库,但通过编程到接口而不是类来解决此类问题是这里的关键。再次强调这一点:
- 如果您的
构造函数正在连接到端点,您将无法模拟此代码。UnitTests永远不应该依赖于另一个可用的端点,即使之后您替换了该实例new Service()
- 如果
不提供可模拟的接口服务
且其方法不是虚拟的,则您将无法对其进行模拟。您需要创建一个包装器接口和实现iSeries设备
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);
}
}
再次强调这一点:
- 如果您的
构造函数正在连接到端点,您将无法模拟此代码。UnitTests永远不应该依赖于另一个可用的端点,即使之后您替换了该实例new Service()
- 如果
不提供可模拟的接口服务
且其方法不是虚拟的,则您将无法对其进行模拟。您需要创建一个包装器接口和实现iSeries设备
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);
}
}
服务是一个实例,所以您不能模拟它。服务应该实现一个接口,然后你们可以模拟它,你们真的应该在那个时候注入它point@BigDaddy我可以创建一个服务可以实现的接口,但是通过ctor注入,创建服务的工作被转移到其他地方。客户的意图是创建服务。这不是客户“使用”服务的意图吗。你需要依赖于抽象,而不是具体。这样做也不需要DI容器。客户端的实例化器可以注入服务。若你们想做单元测试,你们需要注入你们的依赖项。服务是一个实例,所以你们不能模仿它。服务应该实现一个接口,然后你们可以模拟它,你们真的应该在那个时候注入它point@BigDaddy我可以创建一个服务可以实现的接口,但是通过ctor注入,创建服务的工作被转移到其他地方。客户的意图是创建服务。这不是客户“使用”服务的意图吗。你需要依赖于抽象,而不是具体。这样做也不需要DI容器。客户端的实例化器可以注入服务。如果你想做单元测试,你需要注入你的依赖项。你能扩展一下“类不应该实例化服务”吗?客户机的意图是私下处理服务,所以没有其他类需要了解服务或与服务耦合。但是,你不能嘲笑它。也许你可以在上面添加一些模式,也许是一些工厂。但是如果“没有其他类需要知道发生了什么”,它看起来像是封装的,因此您的测试也不应该知道它。问题不是其他类可以知道您的服务。问题是,现在的情况是,您的类除了具体的服务之外什么都不知道。因此,您不能将其解耦并使用另一个“假服务”代替