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

Moq调用参数后续调用变更问题:验证结果不符合预期

问题:Moq验证参数时因引用类型导致调用次数不符

Processor类会两次调用IService的DoSomething方法,传入同一个InputParameters对象:先设置x=5,修改x=100后再次调用。单元测试期望验证DoSomething分别以x=5和x=100各被调用一次,但实际验证显示两次调用的x值均为100。调试发现第一次调用的参数在修改x=100时被改变,疑惑Moq为何仅保存参数引用,且尝试不同Setup配置后结果一致。

代码示例

InputParameters类

public class InputParameters
{
   public int x, y;
}

IService接口与Service实现

public interface IService
{
   bool DoSomething(InputParameters input);
}

public class Service : IService
{
   public bool DoSomething(InputParameters input)
   {
      return input.x > input.y;
   }
}

Processor类

public class Processor
{
   public IService _service;

   public Processor(IService theServive)
   {
      _service = theServive;
   }

   public void Process()
   {
      InputParameters input = new InputParameters();
      input.x = 5;
      input.y = 50;

      _service.DoSomething(input);

      input.x = 100;
      _service.DoSomething(input);
   }
}

单元测试代码

private Mock<IService> _serviceMock;
private Processor _processor;

[SetUp]
public void Setup()
{
   _serviceMock = new Mock<IService>();
   _processor = new Processor(_serviceMock.Object);
}

[Test]
public void Test()
{
   _serviceMock.Setup(service => service.DoSomething(
      It.IsAny<InputParameters>()
   )).Returns(() => false);

   _processor.Process();

   _serviceMock.Verify(service => service.DoSomething(
      It.Is<InputParameters>(input => input.x == 5)
   ), Times.Exactly(1)); // 返回0次调用

   _serviceMock.Verify(service => service.DoSomething(
      It.Is<InputParameters>(input => input.x == 100)
   ), Times.Exactly(1)); // 返回2次调用
}

尝试过的其他Setup配置

_serviceMock.Setup(service => service.DoSomething(
   It.Is<InputParameters>(input => input.x == 5)
)).Returns(() => true);

_serviceMock.Setup(service => service.DoSomething(
   It.Is<InputParameters>(input => input.x == 100)
)).Returns(() => false);

原因与解决方案

问题原因

这是因为InputParameters是引用类型,Moq在记录方法调用时,保存的是对象的引用而非调用时刻的参数快照。当你在第一次调用后修改对象的x值,Moq执行验证逻辑时访问的是同一个对象的当前状态,因此两次验证都会匹配x=100。

解决方法

方法1:每次调用创建新的参数对象

避免复用同一个引用对象,每次调用都实例化新的InputParameters:

public void Process()
{
    // 第一次调用用新对象
    var input1 = new InputParameters { x = 5, y = 50 };
    _service.DoSomething(input1);

    // 第二次调用用另一个新对象
    var input2 = new InputParameters { x = 100, y = 50 };
    _service.DoSomething(input2);
}

方法2:捕获调用时的参数快照

如果必须复用对象,可以在Moq中通过Callback捕获每次调用时的参数状态,直接记录当时的x值:

[Test]
public void Test()
{
    var capturedXValues = new List<int>();
    _serviceMock.Setup(s => s.DoSomething(It.IsAny<InputParameters>()))
                // 每次调用时记录当前x值
                .Callback<InputParameters>(input => capturedXValues.Add(input.x))
                .Returns(false);

    _processor.Process();

    // 验证捕获的x值序列是否符合预期
    Assert.That(capturedXValues, Is.EqualTo(new List<int> { 5, 100 }));
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.09 12:15:38