简体   繁体   English

使用单元测试模拟 OperationCanceledException 场景失败

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

I use Moq 4.18.2 framework for my tests.我使用 Moq 4.18.2 框架进行测试。

The RtspClient might throw an OperationCanceledException from ConnectAsync . RtspClient可能会从ConnectAsync引发OperationCanceledException So, I try to test this scenario.所以,我尝试测试这种情况。 My test below throws an exception System.OperationCanceledException: The operation was canceled.我下面的测试抛出异常System.OperationCanceledException: The operation was canceled. and the catch (OperationCanceledException) never gets executed.并且catch (OperationCanceledException)永远不会被执行。 What am I doing wrong here?我在这里做错了什么?

RTSP RTSP

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

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

Method that uses IRtspClient使用 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;
    }
}

Test测试

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

UPDATE Added missing await as suggested by @Dai, but my test still fails.更新按照@Dai 的建议添加了缺少的await ,但我的测试仍然失败。 Can anyone take a look at the test code?任何人都可以看一下测试代码吗?

  • You need to await the returned Task inside the try{} block - otherwise synchronous control will immediately leave the try{} block.您需要在try{}await返回的Task - 否则同步控制将立即离开try{}块。
  • Exceptions thrown inside an anonymous function (or local function, or lambda method, or ye olde school delegate() local) will not be caught by the catch .在匿名 function(或本地 function,或 lambda 方法,或老派delegate()本地)中抛出的异常将不会被catch
  • Also, CancellationTokenSource is IDisposable , so you should change your ConnectAsync_Canceled test to wrap it in a using() block.此外, CancellationTokenSourceIDisposable ,因此您应该更改ConnectAsync_Canceled测试以将其包装在using()块中。
  • Also, don't swallow exceptions - so my code below captures both exceptions for possible investigation.另外,不要吞下异常——所以我下面的代码捕获了这两个异常以进行可能的调查。

Change your code to this:将您的代码更改为:

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.
    }
}

I found my mistake (in addition to what @Dai noticed).我发现了我的错误(除了@Dai 注意到的)。 I should have either put await camera.ConnectAsync from my test in try-catch or used Assert.ThrowsExceptionAsync .我应该将我的测试中的await camera.ConnectAsync放在try-catch或使用Assert.ThrowsExceptionAsync I chose the latter.我选择了后者。 Here is the working test:这是工作测试:

[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