8

今日、私は async/await について多くのことを読み、完全に心を打たれました。次のテストに合格した理由がわかりません。

[Test]
public void Test()
{
    var listener = new AsyncHttpListener();
    listener.ListeningAsync();

    try
    {
        new WebClient().DownloadString("http://localhost:8080/");
    }
    catch (Exception)
    {
    }

    listener.Close();
}

public class AsyncHttpListener
{
    private readonly HttpListener listener;

    public AsyncHttpListener()
    {
        listener = new HttpListener();
        listener.Prefixes.Add("http://localhost:8080/");
        listener.Start();
    }

    public void Close()
    {
        listener.Close();
    }

    public async void ListeningAsync()
    {
        var context = await listener.GetContextAsync();
        HandleContext(context);
    }

    private void HandleContext(HttpListenerContext context)
    {
        throw new Exception("test excpetion");
    }
}


テストはパスしましたが、出力には以下が含まれます:

System.Exception
テスト例外
   AsyncHttpListenerTest.AsyncHttpListener.HandleContext(HttpListenerContext context) で AsyncHttpListener.cs: 行 30
   AsyncHttpListenerTest.AsyncHttpListener.d__0.MoveNext() で AsyncHttpListener.cs: 25 行目
--- 例外がスローされた前の場所からのスタック トレースの終わり ---
   System.Runtime.CompilerServices.AsyncMethodBuilderCore.b__1 (オブジェクトの状態) で
   System.Threading.ExecutionContext.RunInternal (ExecutionContext executionContext、ContextCallback コールバック、オブジェクトの状態、ブール値の preserveSyncCtx) で
   System.Threading.ExecutionContext.Run (ExecutionContext executionContext、ContextCallback コールバック、オブジェクトの状態、ブール値の preserveSyncCtx) で
   System.Threading.QueueUserWorkItemCallback.System.Threading.IThreadPoolWorkItem.ExecuteWorkItem() で
   System.Threading.ThreadPoolWorkQueue.Dispatch() で

例外がタスク スレッド (HandleContext() メソッド) から呼び出し元コンテキストに送信され、テストが失敗することを期待しています。どうすればこの動作を取得できますか?

4

1 に答える 1

13

async Taskの代わりにメソッドを作成し、の代わりにasync voidテストメソッドを作成します。async Taskvoid

public async Task ListeningAsync()
{
    var context = await listener.GetContextAsync();
    HandleContext(context);
}

[Test]
public async Task Test()
{
    var listener = new AsyncHttpListener();
    await listener.ListeningAsync();

    try
    {
        new WebClient().DownloadString("http://localhost:8080/");
    }
    catch (Exception)
    {
    }

    listener.Close();
}

避けるべきいくつかの正当な理由がありますasync void。エラーハンドリングもその一つです。メソッドから発生したエラーは、メソッドが開始されたときに最新だった にasync void直接行きます。SynchronizationContext

テストに合格した理由は、asyncメソッドが完了する前に呼び出し元に戻る可能性があるためです。テスト ランナーは、テスト メソッドが (まだ例外をスローすることなく) 返されたことを確認し、それを「合格」としてマークします。テスト メソッドから戻った場合、テスト ランナーは、テストが完了したと見なす前に が完了するTaskのを待つ必要があることを認識しています。Task

于 2013-01-17T13:25:31.883 に答える