2

私は私のテストで以下の構造を持っています。これは、特定のログが正しい複雑な引数オブジェクトで呼び出されていることをテストすることを目的としています。logThing にはメソッドがあります。

void AddEntry(LogEntry);

そのため、When..Do を使用して例外をスローさせています。

public void UnitTest()
{
    // Arrange
    ILogThing logThing = Substitute.For<ILogThing>()
    SystemUnderTest system = new SystemUnderTest(logThing);

    List<LogEntry> actualEntries = new List<LogEntry>();
    LogEntry expectedEntry = GetSomeTestData();

    logThing.When(
        lt => lt.AddEntry(Arg.Do<LogEntry>(r => actualEntries.Add(r)))).Do(
        call => { throw new InvalidOperationException("testMessage"); });

    // Act
    try
    {
        system.DoSomethingWhichLogs(someArgs)
    }
    catch(WrappedException ex)
    {
        // Assert
        Assert.AreEqual(1, actualEntries.Count);
        Assert.AreEqual(actualEntries[0], expectedEntry);
    }
}

ただし、Arg.Do() への予想される呼び出しは、このセットアップでは発生しません。

catch ブロックにブレークポイントを配置し、Visual Studio のイミディエイト ウィンドウを使用して、logThing で RecievedCalls<>() を呼び出しました。正しい引数を使用して logThing を 1 回呼び出した記録があります。Arg.Do だけです。 When..Do ブロックが終了した後にのみ実行されるようです。これは明らかに、When..Do を投入しているため、到達しないことを意味します。

NSubstitute がこのような方法で呼び出しを行うとは本当に予想していませんでした。これは予想される動作ですか? もしそうなら、このように入ってくる引数をテストするために私ができることはありますか、それとも引数のチェックをメインの When..Do ブロックに入れる必要がありますか (読みにくくなります)?

テスト中のシステムは、logEntry と一緒にラップするなど、例外に対してさまざまなことを行うため、これらすべてのチェックを 1 つのテストで行うと便利です。2 つの別々のテストに分割することを考えましたが、実現しました私がそれをした場合、間違ったラップされた出力がどこから来ているのかを簡単に突き止めることができませんでした(logEntryを最初に生成した部分、またはそれをラップした部分のいずれかである可能性があります)一方、このパターンを使用して確認できますlogThing は私が期待するものを受け取っています。それでも、それを行うためのより良い方法があれば、私は確かに提案を受け入れます.

4

1 に答える 1

2

When..Do と Arg.Do の正確な順序は定義されておらず、実装に応じてバージョン間で変更される可能性があるため、それを当てにすることはお勧めしません。(特定の順序で定義する正当な理由がある場合は、提案をusergroupに投稿してください。)

logThing が予期した LogEntry を受信したことを確認したいだけの場合は、Arg.Is() を使用して事後引数を確認できます。

logThing.Received().AddEntry(Arg.Is(expectedEntry));

より複雑な比較ロジックが必要な場合は、同じことを行うことができますが、メソッドを使用して引数をチェックします。

logThing.Received().AddEntry(Arg.Is<LogEntry>(x => CheckLogEntry(x)));

CheckLogEntry必要なすべてのチェックを行うことができ、以前のように When..Do スローを維持できます。

When..Do アプローチを使用する必要がある場合は、既存のアプローチを維持できますが、引数のキャプチャを呼び出しに移動して、Do予想される呼び出しの順序を確保できます。

logThing.When(
    lt => lt.AddEntry(Arg.Any<LogEntry>())).Do(
    call =>
    {
        actualEntries.Add(call.Arg<LogEntry>());
        throw new InvalidOperationException("testMessage");
    });

これをテストする他の方法の提案に関しては、ここで何をしようとしているのか完全にはわかりませんが、ラップされた出力がどこから来ているのかを特定するのに問題がある場合は、この責任を別の依存関係に移すことができますか? これにより、この依存関係を置き換えて、このテストの観点からこれが発生した場所を正確に制御できます。

于 2011-09-29T09:45:15.867 に答える