使用另一个模拟验证集将返回 null

本文关键字:返回 null 验证 另一个 模拟 | 更新日期: 2023-09-27 18:36:22

模拟框架:最小起订量
测试框架:NUnit

我觉得这个问题有一个简单的答案,我只是忽略了它,但我一辈子都无法弄清楚为什么这让我感到悲伤。

这里有两个模拟,我正在尝试验证被测试单元是否将一个模拟的属性设置为另一个模拟的属性,如下所示:

[TestFixture]
public class Testmock
{
  protected Mock<IOne> mockOne;
  protected Mock<ITwo> mockTwo;
  protected Controller UnitUnderTest;
  [SetUp]
  public void Setup()
  {
    mockOne = new Mock<IOne>();
    mockTwo = new Mock<ITwo>();
    UnitUnderTest = new Controller(mockOne.Object, mockTwo.Object);
  }
  [Test]
  public void Test1()
  {
    string testString = "test";
    mockOne.SetupGet(o => o.Val).Returns(testString);
    UnitUnderTest.CopyVal();
    mockTwo.VerifySet(t => t.Val = mockOne.Object.Val);
  }
}

public interface IOne
{
  string Val { get; set; }
}
public interface ITwo
{
  string Val { get; set; }
}
public class Controller
{
  IOne one;
  ITwo two;
  public Controller(IOne one, ITwo two)
  {
    this.one = one;
    this.two = two;
  }
  public void CopyVal()
  {
    two.Val = one.Val;
  }
}

当我运行此测试时,它会在VerifySet返回一个错误,内容为:

预期对模拟的调用至少一次,但从未执行过:t => t.Val = (字符串)null

但在此之下,说:

执行的调用:ITwo.Val = "test"

所以我肯定知道ITwo.Val在我的Controller中设置了IOne.Val,但我一定在这里为 VerifySet 设置了错误的模拟。我可以直接用字符串替换验证集,例如:

mockTwo.VerifySet(t => t.Val = testString);

并且测试将通过。由于mockOne.Object.Val SetupGet返回testString,我不太明白为什么我不能在VerifySet中使用mockOne.Object.Val代替testString

使用另一个模拟验证集将返回 null

我不确定为什么 mockOne.Object.Val 在 VerifySet 的上下文中返回 null。我相信这与 Moq 内部实现有关(挖掘 Moq 来源可以揭示这种行为的原因)。

但是,我可以告诉您如何更改测试以使其正常工作,而无需在VerifySet()中使用testString变量。您应该使用 It.Is(x => x == mockOne.Object.Val),而不是直接引用 mock 属性。请看下面:

[Test]
public void Test1()
{
    string testString = "test";
    mockOne.SetupGet(o => o.Val).Returns(testString);
    UnitUnderTest.CopyVal();
    mockTwo.VerifySet(t => t.Val = It.Is<string>(x => x == mockOne.Object.Val));
}

希望这有帮助。