我对异步/等待模式非常熟悉,但我遇到了一些让我觉得奇怪的行为。我确信它发生的原因是完全正当的,我很想了解这种行为。
这里的背景是我正在开发一个 Windows 应用商店应用程序,并且由于我是一个谨慎、认真的开发人员,我正在对所有内容进行单元测试。我很快发现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");
}
}
瞧,它工作得很好。
所以我继续愉快地编写我的单元测试,直到我遇到一个我想确认的异步方法在某些情况下抛出异常。“没问题,”我心想,“我可以传入一个异步 lambda!”
所以我写了这个测试方法:
[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
我只是将 lambda 塞入其中。我知道 lambda 会很高兴地分配给Action
or Func<Task>
。