[英]How to use Moq object correctly when object is parameter in method
I am not completely new to unit testing, however I am new to the Moq library and I have run into a problem. 我对单元测试并不完全陌生,但是对于Moq库我并不陌生,并且遇到了问题。 I am confused on why my unit test fails.
我对为什么我的单元测试失败感到困惑。 Here is the unit test I am trying to write.
这是我要编写的单元测试。
[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
}
The line commented out is the only way I can get the test to pass, but I feel I should be able to use a mock dictionary as well. 注释掉的行是我可以通过测试的唯一方法,但是我觉得我也应该可以使用模拟字典。 The problem I am experiencing is that eventually sut.Open(...) makes a call to an internal class that has an IDictionary as a parameter.
我遇到的问题是,最终sut.Open(...)对具有IDictionary作为参数的内部类进行了调用。 In that method there is a check to see if the dictionary is null.
在该方法中,将检查字典是否为空。 Whenever I run the unit test without a real dictionary, the null check always evaluates to true and I get a false fail.
每当我在没有真正词典的情况下运行单元测试时,null检查总会得出true,而我会得到错误的失败。 However if the real dictionary is passed in, I get a passing test.
但是,如果通过了真正的词典,我会通过测试。 Here is an example of the internal code.
这是内部代码的示例。
public int Open(..., IDictionary<string, string> dictionary, ...)
{
//...
if(!dictionary.ContainsKey(key))
{
dictionary.Add(key, true);
}
InternalClass.Method(dictionary);
//...
}
Here is the internal classes method 这是内部类方法
public void Method(IDictionary<string, string> dictionary)
{
if(dictionary != null && dictionary.ContainsKey(key))
{
string value = dictionary[key];
//... Do something
}
else
{
//... Do something else
}
}
It always executes Do something else, is there away around this? 它总是执行其他操作,这周围还存在吗?
Look closer to the following line: 仔细查看以下行:
optionsMock.Setup(a => a.ContainsKey(It.Is<string>(b => b == keyValue))).Returns(false);
This means ContainsKey
should return false
. 这意味着
ContainsKey
应该返回false
。 So the condition: 因此条件:
if (dictionary != null && dictionary.ContainsKey(key))
can never be satisfied. 永远无法满足。
I guess you meant to write .Returns(true);
我猜你打算写
.Returns(true);
Alright so I think this is the answer I am happy with. 好吧,我认为这是我很满意的答案。 I found some other places online where this was used by other people as well.
我在网上找到了其他人也使用过的其他地方。 Here is the Setup and Verify section now
现在是“设置和验证”部分
bool firstCall = true;
optionsMock.Setup(a => a.ContainsKey(It.Is<string>(b => b == keyValue))).Returns(() =>
{
if (firstCall)
{
firstCall = false;
return false;
}
return true;
});
Then I verify below with the following: 然后,我通过以下内容进行验证:
optionsMock.Verify(a => a.ContainsKey(It.Is<string>(b => b == fullPath)), Times.Exactly(2));
The only thing I don't like about this, is the added logic in the test :(. However I don't see any other way around it. Thanks for all the help! 关于此,我唯一不喜欢的是在测试中添加了逻辑:(。但是我看不到其他方法。感谢所有帮助!
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.