当对象是方法中的参数时,如何正确使用Moq对象

时间:2015-03-06 20:23:45

标签: c# unit-testing dictionary

我不是单元测试的新手,但是我是Moq库的新手,我遇到了一个问题。我很困惑为什么我的单元测试失败了。这是我试图编写的单元测试。

[TestInitialize]
    public void SetUp()
    {
        //...
        optionsMock = new Mock<IDictionary<string, string>>();
        //...
    }

[TestMethod]
    public void TestFunction()
    {
        // Arrange
        //var options = new Dictionary<string, string>() { { keyValue, true.ToString() } }; // only way to get the unit test to pass right now
        optionsMock.Setup(a => a.ContainsKey(It.Is<string>(b => b == keyValue))).Returns(false);
        optionsMock.Setup(c => c.Add(It.Is<string>(d => d == keyValue), It.Is<string>(e => e == true.ToString()))).Verifiable();
        optionsMock.Setup(f => f.ContainsKey(It.Is<string>(g => g == keyValue))).Returns(true);
        optionsMock.Setup(h => h[It.Is<string>(i => i == keyValue)]).Returns(true.ToString()); 

        // Act
        int projectId = sut.Open(stringValue, booleanValue, stringValue, stringValue, IDictionary<string, string>, out errorString);

        // Assert
        optionsMock.Verify(a => a.ContainsKey(It.Is<string>(b => b == keyValue)), Times.Once());
        optionsMock.Verify(c => c.Add(It.Is<string>(d => d == keyValue), It.Is<string>(e => e == true.ToString())), Times.Once());
        optionsMock.Verify(f => f.ContainsKey(It.Is<string>(g => g == keyValue)), Times.Once());
        optionsMock.Verify(h => h[It.Is<string>(i => i == keyValue)], Times.Once()); // This fails 
        Assert.AreNotEqual(0, id); // This fails even if I remove the line above
    }

注释掉的行是我可以通过测试的唯一方法,但我觉得我也应该能够使用模拟字典。我遇到的问题是最终sut.Open(...)调用一个内部类,它有一个IDictionary作为参数。在该方法中,检查字典是否为空。每当我在没有真实字典的情况下运行单元测试时,null检查总是计算为true,并且我得到一个错误的失败。但是,如果传入真正的字典,我会通过测试。以下是内部代码的示例。

public int Open(..., IDictionary<string, string> dictionary, ...)
    {
        //...
        if(!dictionary.ContainsKey(key))
        {
           dictionary.Add(key, true);
        }

        InternalClass.Method(dictionary);
        //...
    }

这是内部类方法

public void Method(IDictionary<string, string> dictionary)
    {
       if(dictionary != null && dictionary.ContainsKey(key))
       {
          string value = dictionary[key];
          //... Do something
       }
       else
       {
          //... Do something else
       }
    }

它总是执行其他的东西,它周围存在吗?

2 个答案:

答案 0 :(得分:0)

仔细观察以下一行:

optionsMock.Setup(a => a.ContainsKey(It.Is<string>(b => b == keyValue))).Returns(false);

这意味着ContainsKey应该返回false。所以条件:

if (dictionary != null && dictionary.ContainsKey(key))

永远不会满足。

我想你打算写.Returns(true);

答案 1 :(得分:-1)

好吧所以我认为这是我很满意的答案。我在网上发现了一些其他人也使用过的地方。现在是“设置和验证”部分

bool firstCall = true;

        optionsMock.Setup(a => a.ContainsKey(It.Is<string>(b => b == keyValue))).Returns(() =>
        {
            if (firstCall)
            {
                firstCall = false;
                return false;
            }

            return true;
        });

然后我在下面用以下内容验证:

optionsMock.Verify(a => a.ContainsKey(It.Is<string>(b => b == fullPath)), Times.Exactly(2));

我唯一不喜欢的是测试中增加的逻辑:(但是我没有看到任何其他方法。感谢所有的帮助!