Я довольно хорошо знаком с шаблоном async/await, но я натыкаюсь на какое-то поведение, которое поражает меня как странное. Я уверен, что существует вполне обоснованная причина, почему это происходит, и я хотел бы понять поведение.
Фон здесь заключается в том, что я разрабатываю приложение для Windows Store, и, поскольку я осторожный, добросовестный разработчик, я все тестирую. Я довольно быстро обнаружил, что ExpectedExceptionAttribute
не существует для WSA. Странно, правда? Ну, не проблема! Я могу больше или меньше реплицировать поведение с помощью метода расширения! Поэтому я написал следующее:
public static class TestHelpers
{
// There 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>();
}
Я в порядке с моим решением, мне просто интересно, почему все идет грушевидно, когда я пытаюсь вызвать async Action
. Я угадываю, потому что, насколько касается времени выполнения, это не Action
, я просто забиваю лямбду в нее. Я знаю, что лямбда с радостью будет назначена либо Action
, либо Func<Task>
.