簡體   English   中英

使用單元測試模擬 OperationCanceledException 場景失敗

[英]Imitation of OperationCanceledException scenario with unit-test fails

我使用 Moq 4.18.2 框架進行測試。

RtspClient可能會從ConnectAsync引發OperationCanceledException 所以,我嘗試測試這種情況。 我下面的測試拋出異常System.OperationCanceledException: The operation was canceled. 並且catch (OperationCanceledException)永遠不會被執行。 我在這里做錯了什么?

RTSP

public interface IRtspClient : IDisposable
{
    event EventHandler<RawFrame> FrameReceived;

    Task ConnectAsync(CancellationToken token);
    Task ReceiveAsync(CancellationToken token);
}

使用 IRtspClient 的方法

public async Task ConnectAsync(CancellationToken token = default)
{
    try
    {
        await _rtspClient.ConnectAsync(token).ConfigureAwait(false);
        OnConnected();
    }
    catch (OperationCanceledException ex)
    {
        OnConnectAttemptCanceled(ex);
        throw;
    }
    catch(Exception ex)
    {
        OnFailedToConnect(ex);
        throw;
    }
}

測試

[TestMethod]
public async Task ConnectAsync_Canceled()
{
    var expectedCanceledTaskStatus = true;

    var tcs = new CancellationTokenSource();
    tcs.Cancel();
    var rtspClient = new Mock<IRtspClient>();
    rtspClient
        .Setup(_ => _.ConnectAsync(It.IsAny<CancellationToken>()))
        .Returns(Task.FromException<OperationCanceledException>(new OperationCanceledException()))

    var actualCanceledTaskStatus = false;
    var camera = new MyCamera(rtspClient.Object);
    camera.FailedToConnect += () => actualCanceledTaskStatus = true;
    await camera.ConnectAsync(tcs.Token);

    Assert.AreEqual(expectedCanceledTaskStatus, actualCanceledTaskStatus);
}

更新按照@Dai 的建議添加了缺少的await ,但我的測試仍然失敗。 任何人都可以看一下測試代碼嗎?

  • 您需要在try{}await返回的Task - 否則同步控制將立即離開try{}塊。
  • 在匿名 function(或本地 function,或 lambda 方法,或老派delegate()本地)中拋出的異常將不會被catch
  • 此外, CancellationTokenSourceIDisposable ,因此您應該更改ConnectAsync_Canceled測試以將其包裝在using()塊中。
  • 另外,不要吞下異常——所以我下面的代碼捕獲了這兩個異常以進行可能的調查。

將您的代碼更改為:

public async Task ConnectAsync( CancellationToken cancellationToken = default )
{
    try
    {
         await this.rtspClient.ConnectAsync(cancellationToken ).ConfigureAwait(false);

         this.OnConnected();
    }
    catch( OperationCanceledException cEx )
    {
        this.OnConnectAttemptCanceled( cEx );

        throw; // Re-throw so the `Task` representing *this method* (`ConnectAsync`) will report as Cancelled rather than Succeeded.
    }
    catch( Exception ex ) 
    {
        this.OnFailedToConnect( ex );

        throw; // Re-throw so the `Task` representing *this method* (`ConnectAsync`) will report as Failed rather than Succeeded.
    }
}

我發現了我的錯誤(除了@Dai 注意到的)。 我應該將我的測試中的await camera.ConnectAsync放在try-catch或使用Assert.ThrowsExceptionAsync 我選擇了后者。 這是工作測試:

[TestMethod]
public async Task ConnectAsync_Canceled()
{
    var expectedTaskCanceledStatus = true;

    var rtspClient = new Mock<IRtspClient>();
    rtspClient
        .Setup(_ => _.ConnectAsync(default(CancellationToken)))
        .Returns(Task.FromException(new OperationCanceledException()));

    var actualTaskCanceledStatus = false;
    var camera = new MyCamera(rtspClient.Object);
    camera.ConnectAttemptCanceled += () => actualTaskCanceledStatus = true;

    await Assert.ThrowsExceptionAsync<OperationCanceledException>(async () => await camera.ConnectAsync());
    Assert.AreEqual(expectedTaskCanceledStatus, actualTaskCanceledStatus);
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM