2013-06-13 17 views
5

カスタムSynchronizationContext実装の周りに単体テストを作成しようとしています。実装が同期または非同期であることをテストするにはどうすればよいですか?

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

この動作を確認するために、単体テストを記述したいと思います。デリゲートは同期または非同期で実行されました。私は、テストが実行中に人為的に延長されるため(遅延を引き起こすのは妥当ですが)、実行時にテストが遅延に依存することを望んでいません。

当初、私は、デリゲートの実行を知らせるためにタスクを使用して検討している:

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がないことを確認するために、コンテキストの周りのテストを手配することができますが、代表者が呼び出さ両方であることを?私の考え組み込む

+1

1 ... :) –

+0

Isnとデリゲートが実行した 'Thread.ManagedThreadId'のポストバックを行うことは可能でしょうか?メインスレッドと同じであれば、同期して実行され、そうでない場合は非同期に実行されます。 – Davio

+0

同期コンテキストでは、呼び出し元スレッドで代理人が実行されないため、恐れはありません。スレッドは単なる実装の詳細です。 –

答えて

-1

:これは実際に動作するかどう

var mainThreadId = Thread.ManagedThreadId; 
var sendThreadId; 
context.Send((state) => sendThreadId = Thread.ManagedThreadId); 
Assert.AreEqual(mainThreadId, sendThreadId); 

は知ってはいけない、あなたがチェックする必要があります。

+0

同期コンテキストでは呼び出し側スレッドで代理人が実行されないため、恐れはありません。スレッドは、非同期プログラミングの実装の詳細です。 –

+0

「同期」と「非同期」は、「同じスレッドで」と「別のスレッドで」と同じではありません。同期メソッドは、別のスレッドでデリゲートを実行し、同期が完了するまで待機します。 – svick

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)); 

:同期のテストのために

質問と名 "Tragedian" の問題を解決する人のための

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(); 
+0

しかし、タイミングが合っていれば非同期メソッドが同期テストに合格する可能性があります。 – svick

+0

あなたは、ブロック解除がタイムアウトする前に、最後のチェックやその他の問題の前にタスクが完了するという事実を参照していますか? – jageall

+0

いいえ、あなたの2番目の 'Assert()'の間に、非同期メソッドが既に実行を開始している可能性があります( 'incall.WaitOne()'が直ちに完了しますが、まだ戻っていないので、 'Status'も'実行中。 – svick

関連する問題