You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何Mock构造函数内初始化的非传入对象?优化代码可测试性

问题解答

1. 当前代码无法Mock GetData的原因

你在MynewClass的构造函数里,明明参数接收了IHttpRestClient实例,却硬编码实例化了HttpRestClient具体类,完全忽略了传入的抽象实例。这种写法直接把依赖钉死在具体实现上,单元测试时根本无法替换成Mock对象。

2. 怎么Mock GetData方法?

核心是放弃在类内部实例化HttpRestClient,直接使用构造函数传入的IHttpRestClient实例。修改MynewClass的构造函数:

class MynewClass: IMynewInterface
{
    private readonly IService1 _service1;
    private readonly IService2 _service2;
    private readonly IHttpRestClient _client;

    public MynewClass(IService1 service1, IService2 service2, IHttpRestClient restclient)
    {
        _service1 = service1;
        _service2 = service2;
        // 直接用传入的抽象实例,不再自己new
        _client = restclient;
    }

    public void MyMethod()
    {
        // Validation logic
        var data = _client.GetData(url);
        // 后续处理
    }
}

之后用Mock框架(比如Moq)就能轻松模拟GetData的行为,示例代码:

// 创建IHttpRestClient的Mock对象
var mockRestClient = new Mock<IHttpRestClient>();
// 模拟GetData方法的返回值
mockRestClient.Setup(c => c.GetData(It.IsAny<string>()))
              .Returns("模拟的返回数据");

// 准备其他依赖的Mock对象
var mockService1 = new Mock<IService1>();
var mockService2 = new Mock<IService2>();

// 实例化MynewClass,传入所有Mock对象
var myClass = new MynewClass(mockService1.Object, mockService2.Object, mockRestClient.Object);

// 调用测试方法
myClass.MyMethod();

// 验证GetData是否被正确调用
mockRestClient.Verify(c => c.GetData(It.IsAny<string>()), Times.Once);

3. 更易于单元测试的代码写法

遵循依赖反转原则和构造函数注入是关键:

  • 永远依赖抽象(比如IHttpRestClient)而非具体实现(HttpRestClient)
  • 所有外部依赖都通过构造函数传入,不在类内部手动实例化
  • 把具体类的实例化工作交给DI容器(比如ASP.NET Core内置容器):在容器中注册IHttpRestClient与HttpRestClient的映射,以及IService1、IService2等依赖,运行时由容器自动注入所有实例。

这样不仅MynewClass的单元测试变得简单,整个项目的依赖关系也更清晰,扩展性更强。

内容的提问来源于stack exchange,提问作者Programmerzzz

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.15 23:02:27