在 MSTest 上调用异步操作时,单元测试预计会引发异常
下面的源代码是关于我的问题的示例代码片段。我预计调用异步操作时会发生异常。
单元测试
[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;
}
}
}
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();
ExceptionWaitHandle.WaitOne();
throw _exception;
}
}
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
也许您可以将异步操作实现为
Task
,从OperateAsync
返回它,然后从调用者返回Task.Wait
?Task.Wait
将“观察”异常,以便您的单元测试可以检测到它(前提是您使用ExpectedException
属性修饰它)。代码如下所示:
请注意,您将从
Task.Wait
获得一个AggregateException
。它的InnerException
将是您从OperateAsync
引发的异常。Perhaps you could implement your asynchronous operation as a
Task
, return it fromOperateAsync
and thenTask.Wait
from the caller?Task.Wait
will "observe" the exception so your unit test can detect it (provided you adorn it withExpectedException
attribute).The code would look like this:
Note that you'll get an
AggregateException
from theTask.Wait
. ItsInnerException
will be the exception you threw fromOperateAsync
.异常发生在不同的线程上,必须进行相应的处理。有几种选择。请查看这两篇文章:
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: