Я довольно знаком с шаблоном async/await, но я натыкаюсь на какое-то поведение, которое поражает меня как нечетное. Я уверен, что есть вполне обоснованная причина, почему это происходит, и я хотел бы понять поведение.Неожиданное поведение при передаче async Действия около
Фон в том, что я разрабатываю приложение для Windows Store, а так как я осторожный, добросовестный разработчик, я все тестирую. Я довольно быстро обнаружил, что ExpectedExceptionAttribute
не существует для WSA. Странно, правда? Ну, не проблема! Я могу больше или меньше реплицировать поведение с помощью метода расширения! Поэтому я написал следующее:
public static class TestHelpers
{
// There's no ExpectedExceptionAttribute for Windows Store apps! Why must Microsoft make my life so hard?!
public static void AssertThrowsExpectedException<T>(this Action a) where T : Exception
{
try
{
a();
}
catch (T)
{
return;
}
Assert.Fail("The expected exception was not thrown");
}
}
И вот, это прекрасно работает.
Итак, я продолжил счастливо записывать свои юнит-тесты, пока не ударил метод асинхронной проверки, который я хотел бы подтвердить, вызывая исключение при определенных обстоятельствах. «Нет проблем, - подумал я про себя, - я могу просто пройти асинхронную лямбду!»
Так что я написал этот метод испытания:
[TestMethod]
public async Task Network_Interface_Being_Unavailable_Throws_Exception()
{
var webManager = new FakeWebManager
{
IsNetworkAvailable = false
};
var am = new AuthenticationManager(webManager);
Action authenticate = async() => await am.Authenticate("foo", "bar");
authenticate.AssertThrowsExpectedException<LoginFailedException>();
}
Это удивительно, возникает ошибка времени выполнения. Это на самом деле аварии тест-бегун!
Я сделал перегрузку моего AssertThrowsExpectedException
метода:
public static async Task AssertThrowsExpectedException<TException>(this Func<Task> a) where TException : Exception
{
try
{
await a();
}
catch (TException)
{
return;
}
Assert.Fail("The expected exception was not thrown");
}
и я отлажены мой тест:
[TestMethod]
public async Task Network_Interface_Being_Unavailable_Throws_Exception()
{
var webManager = new FakeWebManager
{
IsNetworkAvailable = false
};
var am = new AuthenticationManager(webManager);
Func<Task> authenticate = async() => await am.Authenticate("foo", "bar");
await authenticate.AssertThrowsExpectedException<LoginFailedException>();
}
Я в порядке с моим решением, я просто интересно, почему все идет грушевидной, когда я пытаюсь вызвать асинхронный Action
. Я угадываю, потому что, насколько касается времени выполнения, это не a Action
, я просто забиваю лямбду в нее. Я знаю, что лямбда с радостью будет назначена либо Action
, либо Func<Task>
.
В тестах Windows Store используйте 'Assert.ThrowsException', который ([по версии VS2012 Update 2] (http://support.microsoft.com/kb/2797912)) поддерживает 'async' lambdas. Обратите внимание, что 'Action' является * синхронным * методом без возвращаемого значения, а' Func 'является * асинхронным * методом без возвращаемого значения. –
Ох, я не заметил 'Assert.ThrowsException'. Я переключу свои тесты, чтобы использовать это. –