c# – 传递异步操作时出现意外的行为
我非常熟悉异步/等待模式,但我碰到了一些令我奇怪的行为.我相信有一个完全有效的原因,为什么会发生,我很乐意了解行为.
这里的背景是我正在开发一个Windows Store应用程序,由于我是一个谨慎,认真的开发人员,所以我单位测试一切.我很快发现,WSAs不存在ExpectedExceptionAttribute.奇怪,对吧?好吧,没问题!我可以使用扩展方法来复制行为.所以我写道: 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>(); } 我的解决方案很好,我只是想知道为什么一切都变成梨形,当我尝试调用异步Action.我猜是因为,就运行时而言,这不是一个Action,我只是把lambda加入到它里面.我知道lambda将很乐意分配给Action或Func< Task>. 解决方法
在第二个代码片段的情况下,测试人员可能会崩溃并不奇怪:
Action authenticate = async () => await am.Authenticate("foo","bar"); authenticate.AssertThrowsExpectedException<LoginFailedException>(); 当你打电话时,这实际上是一个火灾忘记的an try { a(); } a()立即返回,AssertThrowsExpectedException方法也是如此.同时,一些活动在am.Athenticate内可以在后台继续执行,可能在一个池线程上.究竟发生了什么取决于am.Authenticate的实现,但是当这样的异步操作完成并且它抛出LoginFailedException时,它可能会使您的测试程序崩溃.我不知道单元测试执行环境的同步上下文是什么,但是如果使用默认的SynchronizationContext,那么在这种情况下,异常可能会被抛出不同的线程. VS2012自动支持异步单元测试,只要测试方法签名是异步任务即可.所以,我想你已经回答了你自己的问题,使用await和Func< T>为你的测试. (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |