【问题标题】:Unit tests and multiple async tasks单元测试和多个异步任务
【发布时间】:2016-02-11 14:08:40
【问题描述】:

我正在创建单元测试来帮助构建一些代码,这些代码将接受和排队(如果需要)来自我的控制器的入站请求。

在我的单元测试中,我希望两行代码几乎同时触发,尽管调用之间有 2 秒的延迟。这允许触发我的逻辑的第一个分支,然后在第二次调用时,因为已经看到传递的数据,所以使用了备用逻辑分支。

我已经接近了,但感觉很乱。我正在使用以下代码,它会立即结束我的第一次调用并继续执行后续代码行。

Task.Factory.StartNew(() => stubbedQueueHandler.QueueProcessor(setupModel));

Thread.Sleep(2000);
//second call
stubbedQueueHandler.QueueProcessor(setupModel);

await Task.Delay(10000);

但是,单元测试在第一次调用完成之前结束,这反过来会终止进程。让第一次调用完成的唯一方法是添加一个 await Task.Delay() 行。

我明白它为什么会这样做,因为我已经有效地接听了电话,没有期望得到回复。我不想开始使用任务延迟,而且我确信这只是我对异步编程的理解不足:o)。

【问题讨论】:

    标签: c# asp.net asynchronous asp.net-web-api async-await


    【解决方案1】:

    您需要捕获启动QueueProcessorTask 并在第二次调用存根后等待它:

    public async Task FooTestAsync()
    {
        var task = Task.Run(() => stubbedQueueHandler.QueueProcessor(setupModel));
        await Task.Delay(2000);
    
        stubbedQueueHandler.QueueProcessor(setupModel);
        await task;
    }
    

    这样,您可以确保在操作完成之前完成操作,因为QueueProcessor 将同步阻塞直到其操作完成。

    【讨论】:

      【解决方案2】:

      您需要避免在异步代码中使用 Thread.Sleep()。

      参考Figure 5 The “Async Way” of Doing Things:

      To Do This                                Instead of This            Use This
      Retrieve the result of a background task  Task.Wait or Task.Result   await
      Wait for any task to complete             Task.WaitAny               await Task.WhenAny
      Retrieve the results of multiple tasks    Task.WaitAll               await Task.WhenAll
      Wait a period of time                     Thread.Sleep               await Task.Delay
      

      您应该避免混合使用异步代码和阻塞代码。混合异步和阻塞代码可能会导致死锁、更复杂的错误处理和上下文线程的意外阻塞。

      【讨论】:

      • 好点,我开始养成的一个坏习惯,将在未来将其扼杀在萌芽状态! :o)
      • 这更像是一个评论,而不是对 OPs 问题的回答。
      猜你喜欢
      • 2019-08-02
      • 1970-01-01
      • 1970-01-01
      • 2012-12-26
      • 2012-11-21
      • 2012-12-09
      • 1970-01-01
      • 2012-07-15
      • 1970-01-01
      相关资源
      最近更新 更多