今日、奇妙な問題に遭遇しました。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
オブジェクトは、メソッドPinAttemptsRemaining
に渡される前に値が 2 に減らされます。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 ステートメントが true になり (残りのピン試行回数が変更された)、OnPinAttemptsRemaining
イベントが発生するはずです。ただし、テストは失敗しました (常にではありませんが、コードをゆっくりとステップ実行すると合格しました!)。何が起こっていたかというと、if ステートメントが false_pinAttemptsRemaining
でしinfo.PinAttemptsRemaining
たinfo.PinAttemptsRemaining
。
これを実証するために、コメントを追加しました。
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()
。
以前にこの動作に遭遇した人はいますか? 私はそれへの参照を見つけることができませんでした。