14

非同期操作を実行するメソッドを単体テストしたい:

 Task.Factory.StartNew(() =>
        {
            // method to test and return value
            var result = LongRunningOperation();
        });

単体テスト (c# で記述) で必要なメソッドなどをスタブしますが、問題は、テストをアサートする前に非同期操作が完了していないことです。

どうすればこれを回避できますか? TaskFactory のモックを作成する必要がありますか、または非同期操作を単体テストするためのその他のヒントを作成する必要がありますか?

4

4 に答える 4

7

タスクの作成を偽造する方法が必要になります。

Task.Factory.StartNew呼び出しを依存関係( )に移動した場合は、目的の場所で正確に完了するタスクを作成するためILongRunningOperationStarterに使用される代替実装を作成できます。TaskCompletionSource

少し毛むくじゃらになることもありますが、できます。私はこれについて少し前にブログを書きました-最初にタスクを受け取ったメソッドのユニットテストは、もちろん物事を簡単にしました。これはC#5のasync / awaitのコンテキストにありますが、同じ原則が適用されます。

タスクの作成全体を偽造したくない場合は、タスクファクトリを置き換えて、そのようにタイミングを制御することができますが、正直なところ、それはさらに厄介だと思います。

于 2012-05-11T18:02:36.380 に答える
5

単体テスト用の特別な実装を使用して、メソッドに TaskScheduler をスタブすることを提案します。挿入された TaskScheduler を使用するには、コードを準備する必要があります。

 private TaskScheduler taskScheduler;

 public void OperationAsync()
 {
     Task.Factory.StartNew(
         LongRunningOperation,
         new CancellationToken(),
         TaskCreationOptions.None, 
         taskScheduler);
 }

単体テストでは、このブログ投稿で説明されている DeterministicTaskScheduler を使用して、現在のスレッドで新しいタスクを実行できます。最初の assert ステートメントに到達する前に、「非同期」操作が終了します。

[Test]
public void ShouldExecuteLongRunningOperation()
{
    // Arrange: Inject task scheduler into class under test.
    DeterministicTaskScheduler taskScheduler = new DeterministicTaskScheduler();
    MyClass mc = new MyClass(taskScheduler);

    // Act: Let async operation create new task
    mc.OperationAsync();
    // Act:  Execute task on the current thread.
    taskScheduler.RunTasksUntilIdle();

    // Assert
    ...
}
于 2014-01-02T16:07:18.163 に答える
0

このようなことを試してください...

object result = null;
Task t =  Task.Factory.StartNew(() => result = LongRunningThing()); 


Task.Factory.ContinueWhenAll(new Task[] { t }, () => 
{
   Debug.Assert(result != null);
});
于 2012-05-11T19:42:10.033 に答える