0

今日、奇妙な問題に遭遇しました。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.PinAttemptsRemaininginfo.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()

以前にこの動作に遭遇した人はいますか? 私はそれへの参照を見つけることができませんでした。

4

1 に答える 1

2

私が読んだことから、あなたはモックをテストしようとしています。

sim.Object.UpdateSimInfo(info);

モックは依存関係を置き換えることを目的としています。テストするコードを置き換えるためにモックを使用することはありません。コード全体を見なくても、この動作をテストするのにモックは必要ないと思います。FireOnPinAttemptsRemaining がイベントを発生させると仮定すると、テスト メソッドには次のようなものをお勧めします。

[Test]
public void TestUpdateSimInfoWithPinAttemptsChangedCallsOnPinAttemptsRemaining()
{
    int eventFiredCount = 0;
    var info = new SimPinInfo {PinAttemptsRemaining = 10};
    var sim = Sim(info);
    sim.OnPinAttemptsRemaining += (sender, e) => { eventFiredCount++; };

    info.PinAttemptsRemaining = 2;
    sim.UpdateSimInfo(info);

    Assert.AreEqual(1, eventFiredCount);
}

Fireメソッドがイベントを発生させているかどうか、またはイベント名がわからないため、イベントハンドラーについて100%ではありませんが、アイデアが得られるはずです。

于 2012-11-01T22:04:47.237 に答える