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?
精彩评论