13

だから私はいくつかのコードを持っています

Task.Factory.StartNew(() => this.listener.Start()).ContinueWith(
                    (task) =>
                        {
                            if (task.IsCompleted)
                            {
                                this.status = WorkerStatus.Started;
                                this.RaiseStatusChanged();
                                this.LogInformationMessage("Worker Started.");
                            }
                        });

私がテストしているとき、私はすべての依存オブジェクトをモックしています (namley this.listener.Start())。問題は、ContinueWith を呼び出す前にテストの実行が終了することです。デバッグすると、コードをステップ実行するための余分な遅延のために正常に呼び出されます。

では、別のアセンブリのテスト コードから、テストがアサートにヒットする前にコードが実行されるようにするにはどうすればよいでしょうか。

Thread.Sleep を使用することもできますが、これは非常にハックな方法のようです。

Thread.Join のタスク バージョンを探していると思います。

4

5 に答える 5

2

次の点を考慮してください。

public class SomeClass
{
    public void Foo()
    {
        var a = new Random().Next();
    }
}

public class MyUnitTest
{
    public void MyTestMethod()
    {
        var target = new SomeClass();        
        target.Foo(); // What to assert, what is the result?..
    }
}

に割り当てられた値は何aですか? Foo()結果がメソッドの外部で(戻り値、パブリック プロパティ、イベントなどとして)返されない限り、わかりません。

「予測可能な結果のためにスレッドのアクションを調整する」プロセスは、同期と呼ばれます。

あなたの場合の最も簡単な解決策の 1 つは、Taskクラスのインスタンスを返し、そのWait()メソッドを使用することです。

var task = Task.Factory.StartNew(() => Method1())
    .ContinueWith(() => Method2());

最初のタスクを待つ必要はありません。ContinueWith()は、ターゲット タスクの完了時に非同期で実行される継続を作成するためです( MSDN )。

task.Wait();
于 2012-11-09T13:34:41.640 に答える
2

これを行うための簡単で実用的な方法はないと思います。Thread.Sleep(X) は、問題を回避する最も簡単な (エレガントではないにしても) 方法です。

私が検討した他の唯一の解決策は、テストからモックできるインターフェイスの背後に Task.Factory.StartNew() 呼び出しを隠して、テスト シナリオでタスクの実際の実行を完全に削除することです (ただし、インターフェイスがメソッドが呼び出されます。例:

public interface ITaskWrapper
{
    void TaskMethod();
}

そしてあなたの具体的な実装:

public class MyTask : ITaskWrapper
{
    public void TaskMethod()
    {
        Task.Factory.StartNew(() => DoSomeWork());
    }
}

ITaskWrapper次に、テスト メソッドをモックして、TaskMethod呼び出されることを想定して設定します。

于 2013-10-09T15:02:36.750 に答える
1

処理が終了したときに通知を受ける方法がある場合 (その StatusChanged イベントのハンドラーを追加できますか?)、ManualResetEvent を使用して、適切なタイムアウトで待機します。タイムアウトの期限が切れた場合はテストに失敗します。それ以外の場合は、続行してアサーションを実行します。

例えば

var waitHandle = new ManualResetEvent(false);
sut.StatusChanged += (s, e) => waitHandle.Set();

sut.DoStuff();

Assert.IsTrue(waitHandle.WaitOne(someTimeout), "timeout expired");
// do asserts here
于 2012-11-09T13:31:32.450 に答える
0

ContinueWith()呼び出しの前に最初のタスクが完了しているかどうかに関係なく、継続タスクは引き続き実行されます。これを次のように再確認しました。

// Task immediately exits
var task = Task.Factory.StartNew(() => { });

Thread.Sleep(100);

// Continuation on already-completed task
task.ContinueWith(t => { MessageBox.Show("!"); });

さらにデバッグします。たぶん、あなたの仕事は失敗しています。

于 2012-11-09T13:33:37.803 に答える