Ожидается, что модульный тест вызовет исключение при вызове асинхронной операции на MSTest - PullRequest
3 голосов
/ 01 октября 2011

Исходный код ниже является примером кода моей проблемы.Я ожидаю, что возникнет исключение при вызове асинхронной операции.

Unit Test

[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;
        }
    }
}

Ответы [ 2 ]

2 голосов
/ 01 октября 2011

Возможно, вы могли бы реализовать свою асинхронную операцию как 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();
    }

}

Обратите внимание, что вы получите AggregateException от Task.Wait.Его InnerException будет исключением, которое вы бросили из OperateAsync.

1 голос
/ 01 октября 2011

Исключение возникает в другом потоке и должно обрабатываться соответствующим образом.Есть несколько вариантов.Пожалуйста, посмотрите на эти два сообщения:

...