3

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;
        }
    }
}
Jin-Wook Chung
  • 4,196
  • 1
  • 26
  • 45

2 Answers2

2

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.

Branko Dimitrijevic
  • 50,809
  • 10
  • 93
  • 167
  • +1: Yes, it's right. However, if I use Task instead of Thread, this problem is sovled, but Task cannot throw immediately an unhandled excetion when it is occurred in Task process and a main thread does not wait the task completion. Moreoever, using Task because of a asychronous test seems to be unreasonable. If I have misconception, please let me know about it. Thanks for your answer. – Jin-Wook Chung Oct 01 '11 at 01:54
  • An exception thrown from one thread (whether wrapped by `Task` of not) can never be *directly* caught by another. The reason is simple: exception mechanism relies on stack unwinding and different threads have different stacks. So, however you put it, you'll have to somehow "pack" the exception in "source" thread and "unpack" it in the "target". And since we are talking two different threads here, you'll have to go through some sort of synchronization mechanism (i.e. some kind of "wait"). So, why not use such mechanism that people much smarter than you and me already implemented within `Task`? – Branko Dimitrijevic Oct 01 '11 at 02:07
  • BTW, do you have a specific reason why you think "using Task because of a asychronous test seems to be unreasonable"? – Branko Dimitrijevic Oct 01 '11 at 02:08
  • My idea is that I could use `UnhandledException` event to log or do something when other thead(not main) throws an exception. However, if I use Task and want to receive a exception of the task, it requires waiting the task completion, isn't it? So, I wanted to use Thread instead of Task, though there may be a solution about synchronization of main thread and any task, which is calling SynchronizationContext.Send when the task throws a exception. – Jin-Wook Chung Oct 01 '11 at 02:31
  • **When** do you want to log? If you want to log immediately, why use exceptions at all (ar at least, why not catch them in their thread of origin)? Also, I don't understand why you think a thread would give you any advantage over `Task`. After all, a `Task` wraps a thread. – Branko Dimitrijevic Oct 01 '11 at 02:52
  • BTW, another option for more immediate communication between different thread/tasks is implementing a message queue paradigm (see the `BlockingCollection` class). Also, I warmly recommend reading through "Parallel Programming with Microsoft .NET" (http://msdn.microsoft.com/en-us/library/ff963553.aspx). – Branko Dimitrijevic Oct 01 '11 at 02:58
  • Sorry for reply your response so late. I would you like to tell you what I mean exactly. Thread Exception is centralized into AppDomain.UnhandledException when any unhandled exception was occurred, but Task may be difficult to do so. If you have extra time, please refer to, http://stackoverflow.com/questions/2707295/how-to-handle-all-unhandled-exceptions-when-using-task-parallel-library. – Jin-Wook Chung Oct 07 '11 at 18:38
1

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:

Community
  • 1
  • 1
Igor Pashchuk
  • 2,455
  • 2
  • 22
  • 29