加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

c# – 传递异步操作时出现意外的行为

发布时间:2020-12-15 06:20:31 所属栏目:百科 来源:网络整理
导读:我非常熟悉异步/等待模式,但我碰到了一些令我奇怪的行为.我相信有一个完全有效的原因,为什么会发生,我很乐意了解行为. 这里的背景是我正在开发一个Windows Store应用程序,由于我是一个谨慎,认真的开发人员,所以我单位测试一切.我很快发现,WSAs不存在Expected
我非常熟悉异步/等待模式,但我碰到了一些令我奇怪的行为.我相信有一个完全有效的原因,为什么会发生,我很乐意了解行为.

这里的背景是我正在开发一个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 async void method:

try
{
    a();
}

a()立即返回,AssertThrowsExpectedException方法也是如此.同时,一些活动在am.Athenticate内可以在后台继续执行,可能在一个池线程上.究竟发生了什么取决于am.Authenticate的实现,但是当这样的异步操作完成并且它抛出LoginFailedException时,它可能会使您的测试程序崩溃.我不知道单元测试执行环境的同步上下文是什么,但是如果使用默认的SynchronizationContext,那么在这种情况下,异常可能会被抛出不同的线程.

VS2012自动支持异步单元测试,只要测试方法签名是异步任务即可.所以,我想你已经回答了你自己的问题,使用await和Func< T>为你的测试.

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读