【问题标题】:Using Moq, How do you Mock a method that uses local variables使用 Moq,你如何模拟使用局部变量的方法
【发布时间】:2016-10-20 22:11:24
【问题描述】:

Moq 新手,这是一个非常简单的示例。我想模拟对我的方法“string getCode(int someID)”中使用的“int SmokeTest(int a,int b)”方法的调用。 SmokeTest 的变量在 getCode 中声明和设置。问题是当我模拟对smokeTest 的方法调用时,我总是在getCode 中得到“0”的结果,但我想看到我的预定义结果“20”。我发现的唯一解决方法是重载方法并传入所有变量。但是,我不想这样做,因为我想测试的许多方法都声明和使用局部变量。使用 Moq 测试此方法的最佳方法是什么?谢谢

// Example A
public string getCode(int someID)
{
    int x = 5;
    int y = 5;
    int z = _dataAccess.smokeTest(x, y);

    return _dataAccess.getCode(someID);
}

// NOTE: Doesn't work as wanted
[Test]
public void test_getCode_TestB()
{
    var x = It.IsAny<int>();
    var y = It.IsAny<int>();

    // NOTE: "20" is not returned, 0 is returned instead because local variables are used
    _mockDataAccess.Setup(m => m.smokeTest(x, y)).Returns(20);
    _mockDataAccess.Setup(m => m.getCode(234)).Returns("def345");

    var result = _businessLogic.getCode(234);

    Assert.IsTrue(result == "def345");
}

// Example B

// NOTE: Workaround - pass in variables
public string getCode(int someID, int a, int b)
{
    var c = _dataAccess.smokeTest(a, b);
    return _dataAccess.getCode(someID);
}       

[Test]
public void test_getCode_TestC()
{
    var x = It.IsAny<int>();
    var y = It.IsAny<int>();

    // NOTE: "20" is returned as wanted
    _mockDataAccess.Setup(m => m.smokeTest(x, y)).Returns(20);
    _mockDataAccess.Setup(m => m.getCode(234)).Returns("def345");

    var result = _businessLogic.getCode(234, x, y);
    Assert.IsTrue(result == "def345");
}

【问题讨论】:

  • 替换为 var y 后是否仍然工作错误?

标签: c# unit-testing moq


【解决方案1】:

仅当您将It.IsAny&lt;int&gt;() 直接传递到最小起订量设置时才会起作用:

_mockDataAccess.Setup(m => m.smokeTest(It.IsAny<int>(), It.IsAny<int>())).Returns(20);

我在浏览 moq 源代码时发现这样做:

int x = It.IsAny<int>();
int y = It.IsAny<int>();
_mockDataAccess.Setup(m => m.smokeTest(x, y)).Returns(20);

将 x 和 y 指定为 int 的默认值,即 0,因此您的设置等同于:

_mockDataAccess.Setup(m => m.smokeTest(0, 0)).Returns(20); 

此设置告诉 moq 如果参数为 0 和 0,则返回 20,否则它将返回 int 的默认值,即再次为 0。这不是您要创建的行为,因此在将 It.IsAny&lt;int&gt;() 传递到最小起订量设置之前,您不应将它们分配给 x 和 y。

由于@Rob 注释表明It.IsAny&lt;T&gt; 是一种可以传入moq setup 的存根,setup 方法将知道如何使用Expression Trees 处理它,但该方法实际返回的值始终是默认值T. 这就是为什么我们必须始终直接在最小起订量设置中使用此方法。

【讨论】:

  • @rob23 很高兴能帮上忙,我编辑了答案,提供了有关问题的更多信息,供您参考。
  • 请注意,这是因为模拟库中的一些诡计。 It.IsAny&lt;T&gt;() 可能是一个简单返回 default(T) 的存根。但是,我们将表达式树传递给 Setup() - 这意味着 It.IsAny&lt;T&gt; 并没有真正被库调用,而只是将其用作如何处理参数的指令
  • @Rob 我读了这段代码,我认为这是表达式树的一个很好的用法和一个很好的技巧,但不幸的是它也可以引导框架的新用户处理像这样令人讨厌的错误。
猜你喜欢
  • 1970-01-01
  • 2014-06-07
  • 1970-01-01
  • 2011-04-17
  • 1970-01-01
  • 2010-10-08
  • 2010-11-12
  • 1970-01-01
相关资源
最近更新 更多