gpt4 book ai didi

c# - 传递异步操作时的意外行为

转载 作者:可可西里 更新时间:2023-11-01 09:11:52 25 4
gpt4 key购买 nike

我非常熟悉 async/await 模式,但我遇到了一些让我觉得很奇怪的行为。我确信它的发生有一个完全正当的理由,我很想了解这种行为。

这里的背景是我正在开发一个 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>();
}

我对我的解决方案很好,我只是想知道为什么当我尝试调用异步 Action 时一切都变成梨形.我猜是因为,就运行时而言,它不是 Action ,我只是把 lambda 塞进去。我知道 lambda 会很高兴地分配给 ActionFunc<Task> .

最佳答案

在您的第二个代码片段场景中,它可能会使测试仪崩溃并不奇怪:

Action authenticate = async () => await am.Authenticate("foo", "bar");
authenticate.AssertThrowsExpectedException<LoginFailedException>();

它实际上是对 an async void method 的即发即弃调用,当您调用操作时:

try
{
a();
}

a()立即返回,AssertThrowsExpectedException 也是如此方法。与此同时,内部开始了一些事件am.Authenticate可能会在后台继续执行,可能在池线程上。到底发生了什么取决于 am.Authenticate 的实现,但是当这样的异步操作完成并抛出 LoginFailedException 时,它可能会在以后使您的测试仪崩溃。 .我不确定单元测试执行环境的同步上下文是什么,但是如果它使用默认的 SynchronizationContext ,在这种情况下,异常可能确实在不同的线程上被抛出而不被观察到。

VS2012自动支持异步单元测试,只要测试方法签名为async Task即可。 .所以,我认为您已经通过使用 await 回答了自己的问题。和 Func<T>供您测试。

关于c# - 传递异步操作时的意外行为,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19750379/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com