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

Moq模拟方法未返回预设值却执行真实方法致测试崩溃求助

问题根源

你的Mock不生效的核心原因是:ExpectVariableValue.ExecuteAction方法内部直接硬编码实例化了GetVariable对象,完全没有用到你在测试中创建的Mock<IGetVariable>实例。程序执行时会跳过Mock,直接创建真实的GetVariable对象并调用其真实方法,自然会因为connection为null而崩溃。

解决办法

要让Mock生效,必须重构代码,将IGetVariable的创建逻辑从ExpectVariableValue内部移出,通过依赖注入的方式传入,这样测试时才能用Mock替换真实对象。以下提供两种可行方案:


方案一:直接注入IGetVariable实例(适合变量名固定的场景)

1. 重构ExpectVariableValue类

添加支持依赖注入的构造函数,移除内部硬编码的new GetVariable:

public class ExpectVariableValue
{
    private readonly string _expectedValue;
    private readonly IGetVariable _getVariable;

    // 生产环境构造函数(保留原有调用方式)
    public ExpectVariableValue(string variableName, string expectedValue)
        : this(new GetVariable(variableName), expectedValue)
    {
    }

    // 测试专用构造函数(注入Mock实例)
    public ExpectVariableValue(IGetVariable getVariable, string expectedValue)
    {
        _getVariable = getVariable;
        _expectedValue = expectedValue;
    }

    public virtual ActionResult ExecuteAction(object sender, SimConnect connection)
    {
        // 直接使用注入的IGetVariable实例,不再自己创建
        var result = _getVariable.ExecuteAction(sender, connection);

        string isExpectedValue = CheckIfVariableHasExpectedValue(sender, connection, result.ComputedResult);

        return new ActionResult(isExpectedValue, isExpectedValue, result.Error);
    }

    // 原有CheckIfVariableHasExpectedValue方法...
}

2. 修改测试代码

直接将Mock的IGetVariable实例传入被测对象:

[TestClass]
public class ExpectVariableValueTests
{
    ExpectVariableValue expectedVariableValue;
    Mock<IGetVariable> getVariableMock;

    [TestMethod]
    public void NumericValue_VariableHasTargetValue_TrueIsReturned()
    {
        // 配置Mock的返回值
        getVariableMock = new Mock<IGetVariable>();
        getVariableMock.Setup(x => x.ExecuteAction(It.IsAny<object>(), It.IsAny<SimConnect>()))
                       .Returns(new ActionResult(null, "MyATCID", false));

        // 使用测试构造函数,传入Mock实例
        this.expectedVariableValue = new ExpectVariableValue(getVariableMock.Object, "MyATCID");

        var result = this.expectedVariableValue.ExecuteAction(null, null);

        result.Should().Be("True");
    }
}

方案二:使用工厂模式注入(适合需要动态创建IGetVariable的场景)

如果ExpectVariableValue需要根据不同的变量名创建IGetVariable,可以用工厂模式解耦:

1. 定义工厂接口与实现

// 工厂接口
public interface IGetVariableFactory
{
    IGetVariable Create(string variableName);
}

// 生产环境工厂实现
public class GetVariableFactory : IGetVariableFactory
{
    public IGetVariable Create(string variableName)
    {
        return new GetVariable(variableName);
    }
}

2. 重构ExpectVariableValue类

注入工厂接口,通过工厂创建IGetVariable实例:

public class ExpectVariableValue
{
    private readonly string _variableName;
    private readonly string _expectedValue;
    private readonly IGetVariableFactory _factory;

    // 生产环境构造函数
    public ExpectVariableValue(string variableName, string expectedValue)
        : this(variableName, expectedValue, new GetVariableFactory())
    {
    }

    // 测试专用构造函数
    public ExpectVariableValue(string variableName, string expectedValue, IGetVariableFactory factory)
    {
        _variableName = variableName;
        _expectedValue = expectedValue;
        _factory = factory;
    }

    public virtual ActionResult ExecuteAction(object sender, SimConnect connection)
    {
        // 通过工厂创建IGetVariable实例,不再硬编码
        IGetVariable gv = _factory.Create(_variableName);

        var result = gv.ExecuteAction(sender, connection);

        string isExpectedValue = CheckIfVariableHasExpectedValue(sender, connection, result.ComputedResult);

        return new ActionResult(isExpectedValue, isExpectedValue, result.Error);
    }

    // 原有CheckIfVariableHasExpectedValue方法...
}

3. 修改测试代码

Mock工厂,让它返回预设的IGetVariable实例:

[TestClass]
public class ExpectVariableValueTests
{
    ExpectVariableValue expectedVariableValue;
    Mock<IGetVariable> getVariableMock;
    Mock<IGetVariableFactory> factoryMock;

    [TestMethod]
    public void NumericValue_VariableHasTargetValue_TrueIsReturned()
    {
        // 配置IGetVariable的Mock返回值
        getVariableMock = new Mock<IGetVariable>();
        getVariableMock.Setup(x => x.ExecuteAction(It.IsAny<object>(), It.IsAny<SimConnect>()))
                       .Returns(new ActionResult(null, "MyATCID", false));

        // 配置工厂Mock,让它返回上面的IGetVariable实例
        factoryMock = new Mock<IGetVariableFactory>();
        factoryMock.Setup(f => f.Create("ATC ID"))
                   .Returns(getVariableMock.Object);

        // 注入工厂Mock创建被测对象
        this.expectedVariableValue = new ExpectVariableValue("ATC ID", "MyATCID", factoryMock.Object);

        var result = this.expectedVariableValue.ExecuteAction(null, null);

        result.Should().Be("True");
    }
}
总结

两种方案的核心都是解除ExpectVariableValue对GetVariable的直接依赖,让依赖对象可以从外部传入,这样测试时就能用Moq生成的Mock实例替换真实对象,达到隔离外部依赖、验证逻辑的目的。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.27 10:42:53