单元测试预计在调用MSTest上的异步操作时抛出异常

本文关键字:异步操作 抛出异常 MSTest 调用 单元测试 | 更新日期: 2023-09-27 18:10:06

下面的源代码是关于我的问题的示例代码片段。我期望在调用异步操作时发生异常。

单元测试

[TestMethod()]
[ExpectedException(typeof(Exception))]
public void OperateAsyncTest()
{
    //Arrange
    var testAsyncClass = new TestAsyncClass();
    //Act
    testAsyncClass.OperateAsync();
}

代码
public class TestAsyncClass
{
    public void OperateAsync()
    {
        ThreadPool.QueueUserWorkItem( obj =>{
            throw new Exception("an exception is occurred.");
        });
    }
}

但是,MsTest不能捕获异常,因为可能测试线程与抛出异常的线程不同。如何解决这个问题?任何想法?

下面的代码是我的变通方法,但它既不聪明也不优雅。

解决方案

[TestClass()]
public class TestAsyncClassTest
{
    private static Exception _exception = new Exception();
    private static readonly EventWaitHandle ExceptionWaitHandle = new AutoResetEvent(false);
    static TestAsyncClassTest()
    {
        AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException;
    }
    static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
    {
        _exception = (Exception)e.ExceptionObject;
        ExceptionWaitHandle.Set();
    }

    [TestMethod()]
    [ExpectedException(typeof(Exception))]
    public void OperateAsyncTest()
    {
        //Arrange
        var testAsyncClass = new TestAsyncClass();
        //Act
        lock(_exception)
        {
            testAsyncClass.OperateAsync();
            ExceptionWaitHandle.WaitOne();
            throw _exception;
        }
    }
}

单元测试预计在调用MSTest上的异步操作时抛出异常

也许您可以将您的异步操作实现为Task,从OperateAsync返回,然后从调用者返回Task.Wait ?

Task.Wait将"观察"异常,以便您的单元测试可以检测到它(如果您用ExpectedException属性装饰它)。

代码应该是这样的:

public class TestAsyncClass {
    public Task OperateAsync() {
        return Task.Factory.StartNew(
            () => {
                throw new Exception("an exception is occurred.");
            }
        );
    }
}
[TestClass]
public class TestAsyncClassTest {
    [TestMethod]
    [ExpectedException(typeof(AggregateException))]
    public void OperateAsyncTest() {
        var testAsyncClass = new TestAsyncClass();
        testAsyncClass.OperateAsync().Wait();
    }
}

注意,您将从Task.Wait中获得AggregateException。它的InnerException将是你从OperateAsync抛出的异常。

异常发生在不同的线程上,必须相应地处理。有几个选择。请看看这两篇文章:

  • 异步命令模式-异常处理
  • 异步多线程异常处理?