开发者

Unit test expected to throw an exception when calling an asynchronous operation on MSTest

The source code below is an example code snippet about my problem. I expect an exception to be occurred when an asynchronous operation is called.

Unit Test

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

Code

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

However, MsTest cannot catch the exception because probably, the test thread is different from the thread throwing the exception. How is this problem solved? Any idea?

The following code is my workaround, but it is not smart or elegant.

Workaround

[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();
            ExceptionWaitH开发者_StackOverflow中文版andle.WaitOne();
            throw _exception;
        }
    }
}


Perhaps you could implement your asynchronous operation as a Task, return it from OperateAsync and then Task.Wait from the caller?

Task.Wait will "observe" the exception so your unit test can detect it (provided you adorn it with ExpectedException attribute).

The code would look like this:

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

}

Note that you'll get an AggregateException from the Task.Wait. Its InnerException will be the exception you threw from OperateAsync.


The exception occurs on a different thread and has to be handled accordingly. There are a few options. Please take a look at these two posts:

  • Async command pattern - exception handling
  • Asynchronous Multithreading Exception Handling?
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜