我今天遇到了一个奇怪的问题——我正在围绕一个 SIM 对象编写一个单元测试。它断言当 SIM 对象更新并且剩余的 PIN 尝试已更改时,它将调用特定方法。测试看起来像这样:
[Test]
public void TestUpdateSimInfoWithPinAttemptsChangedCallsOnPinAttemptsRemaining()
{
var info = new SimPinInfo {PinAttemptsRemaining = 10};
var sim = new Mock<Sim>(info);
info.PinAttemptsRemaining = 2;
sim.Object.UpdateSimInfo(info);
sim.Verify(s => s.FireOnPinAttemptsRemaining(), Times.Once());
}
因此,创建模拟 SIM 对象时剩余 10 次 PIN 尝试。然后在传递给方法之前,该SimPinInfo
对象的值减少到 2 。PinAttemptsRemaining
UpdateSimInfo()
SIM 构造函数(为清楚起见进行了修剪):
internal Sim(SimPinInfo info) : this()
{
_pinAttemptsRemaining = info.PinAttemptsRemaining;
_pukAttemptsRemaining = info.PukAttemptsRemaining;
......
}
和UpdateSimInfo()
方法(修剪):
internal void UpdateSimInfo(SimPinInfo info)
{
lock(_locker)
{
if (_pinAttemptsRemaining != info.PinAttemptsRemaining)
{
Log("PinAttemptsRemaining changed");
_pinAttemptsRemaining = info.PinAttemptsRemaining;
FireOnPinAttemptsRemaining();
}
.....
}
}
一个非常简单的测试 - 应该发生的是上面的 if 语句将为真(剩余的 pin 尝试已更改),因此OnPinAttemptsRemaining
将触发事件。然而,测试失败了(虽然不是一直 - 当我慢慢地通过代码时它通过了!)。发生的事情是 if 语句是错误的 - 两者_pinAttemptsRemaining
都是info.PinAttemptsRemaining
2。看起来 SIM 模拟实际上没有按预期创建 - 当info.PinAttemptsRemaining
是 10 时。
为了证明这一点,我添加了一条评论:
var sim = new Mock<Sim>(info);
info.PinAttemptsRemaining = 2;
Console.WriteLine("SIM's pin attempts = " + sim.Object.PinAttemptsRemaining);
我还在 SIM 对象的构造函数中放置了一个断点。跨过线时断点被击中Console.WriteLine
,而不是new Mock...
线。所以在需要之前不会创建对象。
我相信这被称为延迟加载或延迟评估。
这种行为有多种解决方法——我最终创建了一个新SimPinInfo
对象来传递给UpdateSimInfo()
.
有没有人遇到过这种行为?我找不到任何对它的引用。