5

SynchronizationContextカスタム実装に関する単体テストを作成しようとしています。

このクラスの 2 つの重要な操作はSendPostです。ここで、Sendはデリゲートを同期的にPost呼び出し、デリゲートを非同期的に呼び出します。

デリゲートが同期または非同期で実行されたことを確認するために、単体テストを作成したいと思います。テストが成功した場合の遅延に依存することは望ましくありません。これは、テストの実行を人為的に引き延ばすためです (ただし、失敗によって遅延が発生するのは合理的です)。

最初に、タスクを使用してデリゲートの実行を通知することを検討しました。

var tcs = new TaskCompletionSource<object>();

var context = new CustomSynchronizationContext();

context.Send((state) => tcs.SetResult(null), null);

// Task should already be completed!
Assert.IsTrue(this.tcs.Task.IsCompleted);

ただし、これは、テスト ランナーが続行できるようになる前に、デリゲートが非常に迅速に非同期で実行されなかったことを保証するものではありません。

Sendデリゲートの完了をブロックし、ブロックPostしないが、デリゲート両方が呼び出されることを確認するために、コンテキストの周りにテストを配置するにはどうすればよいですか?

4

2 に答える 2

3

ManualResetEventsのペアを使用してこれを達成できると思います。以下のコードを使用すると、テストが失敗した場合にのみスローダウンが発生します (数値はかなり高く、おそらく安全に減らすことができます)。ここでの考え方は、ブロックするかブロックしない場合にのみ発生する可能性のあることが発生する順序をアサートするということです。

同期テストの場合:

var incall = new ManualResetEvent(false);
var unblock = new ManualResetEvent(false);
var context = new CustomSynchronizationContext();
var t = Task.Run(() => context.Send(state =>
{
    incall.Set();
    unblock.WaitOne(5000);
}, null));
Assert.IsTrue(incall.WaitOne(1000));
Assert.IsFalse(t.Wait(10));
unblock.Set();
Assert.IsTrue(t.Wait(1000));

非同期テストの場合:

var incall = new ManualResetEvent(false);
var unblock = new ManualResetEvent(false);
var context = new CustomSynchronizationContext();
var t = Task.Run(() =>context.Post(state =>
{
    incall.Set();
    unblock.WaitOne(5000);
}, null));
Assert.IsTrue(incall.WaitOne(1000));
Assert.IsTrue(t.Wait(1000)); //This will timeout if unblock is blocking completion of the task
unblock.Set();
于 2013-06-17T17:38:28.170 に答える