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

无法注入Mock对象时,如何测试MyMethod返回false并正确重构类?

解决方法:重构以实现可测试性(无需全局依赖注入)

针对你的问题,有两种轻量的重构方案,既不需要引入全局依赖注入,也能完全隔离外部服务器依赖,实现对searchResult == null场景的测试:

方案一:提取连接创建逻辑为受保护虚拟方法

这是改动最小的方案,通过将创建LdapConnection的逻辑封装成受保护的虚拟方法,让测试项目可以通过子类重写来替换连接实例:

1. 重构原类

public class MyConnectionHandler
{
    public bool MyMethod()
    {
        var myConnection = CreateLdapConnection();
        var searchResult = myConnection.Search(...);

        if (searchResult == null) return false;
        return true;
    }

    // 封装连接创建逻辑,供测试重写
    protected virtual LdapConnection CreateLdapConnection()
    {
        return new LdapConnection(...);
    }
}

2. 创建测试用子类

在测试项目中定义子类,重写CreateLdapConnection方法返回Mock的连接实例:

public class TestableMyConnectionHandler : MyConnectionHandler
{
    private readonly LdapConnection _mockConnection;

    public TestableMyConnectionHandler(LdapConnection mockConnection)
    {
        _mockConnection = mockConnection;
    }

    protected override LdapConnection CreateLdapConnection()
    {
        return _mockConnection;
    }
}

3. 编写单元测试

使用Mock框架(如Moq)让Search方法返回null,验证MyMethod返回false:

[Test]
public void MyMethod_WhenSearchResultIsNull_ReturnsFalse()
{
    // Arrange
    var mockLdap = new Mock<LdapConnection>();
    // 替换为实际的Search方法参数
    mockLdap.Setup(c => c.Search(It.IsAny<string>(), It.IsAny<SearchScope>(), ...))
            .Returns(null);

    var handler = new TestableMyConnectionHandler(mockLdap.Object);

    // Act
    var result = handler.MyMethod();

    // Assert
    Assert.IsFalse(result);
}

方案二:使用内部工厂接口

如果更倾向于遵循依赖倒置原则,可通过内部工厂接口封装连接创建逻辑,同时限制接口的可见范围(仅当前程序集和测试项目可见):

1. 重构原类及添加工厂

在MyConnectionHandler所在的程序集中添加内部接口和默认实现:

// 仅当前程序集可见的工厂接口
internal interface ILdapConnectionFactory
{
    LdapConnection Create();
}

// 默认工厂实现
internal class DefaultLdapConnectionFactory : ILdapConnectionFactory
{
    public LdapConnection Create()
    {
        return new LdapConnection(...);
    }
}

public class MyConnectionHandler
{
    private readonly ILdapConnectionFactory _connectionFactory;

    // 对外公开的构造函数,使用默认工厂
    public MyConnectionHandler() : this(new DefaultLdapConnectionFactory())
    {
    }

    // 内部构造函数,仅测试项目可访问
    internal MyConnectionHandler(ILdapConnectionFactory connectionFactory)
    {
        _connectionFactory = connectionFactory;
    }

    public bool MyMethod()
    {
        var myConnection = _connectionFactory.Create();
        var searchResult = myConnection.Search(...);

        if (searchResult == null) return false;
        return true;
    }
}

2. 配置测试项目访问内部成员

在原程序集的AssemblyInfo.cs中添加以下代码,允许测试项目访问内部成员:

[assembly: InternalsVisibleTo("YourTestProjectName")]

3. 编写单元测试

直接Mock工厂和连接实例,注入到MyConnectionHandler中:

[Test]
public void MyMethod_WhenSearchResultIsNull_ReturnsFalse()
{
    // Arrange
    var mockLdap = new Mock<LdapConnection>();
    mockLdap.Setup(c => c.Search(...)).Returns(null);

    var mockFactory = new Mock<ILdapConnectionFactory>();
    mockFactory.Setup(f => f.Create()).Returns(mockLdap.Object);

    var handler = new MyConnectionHandler(mockFactory.Object);

    // Act
    var result = handler.MyMethod();

    // Assert
    Assert.IsFalse(result);
}

方案对比

  • 方案一:代码改动极少,适合简单场景,无需额外类型定义,但依赖子类重写虚拟方法。
  • 方案二:更符合面向设计原则,扩展性更强,若后续需修改连接创建逻辑,无需改动MyConnectionHandler核心代码,但需要额外定义接口和工厂类。

两种方案都完全避免了依赖外部服务器,且无需引入全局依赖注入容器,仅在测试场景下替换连接实例。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.27 20:07:49