如何对带有异步的流进行单元测试
Posted
技术标签:
【中文标题】如何对带有异步的流进行单元测试【英文标题】:How to unit test a flow with async down the line 【发布时间】:2021-06-12 08:26:44 【问题描述】:我有一个以常规函数开始的流程(方法签名中没有异步),然后我调用 Task.Run(await () => asyncFunction())。
除了等待而不期待任何回报是不好的做法之外,有没有一种方法可以运行单元测试来将代码运行到最后? 目前,一旦单元测试完成,需要在 Task.Run 中运行的任务将被取消,因为该任务是异步的并被放在任务队列的末尾(据我所知),主线程完成并且任务没有机会运行。
谢谢
编辑:添加 MVP:
using System;
using System.Threading.Tasks;
namespace SomeNamespace
public class Class1
public void Foo()
Task.Run(async () => await AsyncMethod());
private async Task AsyncMethod()
await Task.Delay(3000);
Console.WriteLine("Waited 3 seconds");
和单元测试:
[TestMethod]
public void Debug2()
var c = new Class1();
c.Foo();
我想执行写行
谢谢
【问题讨论】:
异步函数是否改变任何状态?你能检查那个状态吗?在你的测试中等待,直到观察到状态变化(忙着等待,thread.sleep,...) @knittl 这是个好主意,但不幸的是,异步函数执行无效的非状态更改(如纯函数)逻辑。 @Ace66 如果它没有任何副作用(即是纯的)并且您没有观察到它的返回值,那么它没有做任何有用的事情(如果它没有,程序将是等效的'根本不运行)。 @Ace66 我最初的建议仍然有效:阻塞主线程,直到你观察到你的副作用。无论是忙着等待(while (!logFile.contains("expected));
),“估计”睡眠(Thread.sleep(5000); Assert.That(logFile…)
)还是更复杂的事情(例如注入带有等待句柄的自定义记录器)。如果副作用很重要,请使其可观察到。如果无法观察到,请重构您的代码以使其如此。
@Ace66 [cont'd] ...你写自己“除了这是不好的做法”——现在你知道为什么它被认为是不好的做法:它让你的代码很难测试;)
【参考方案1】:
除了等待而不期待任何回报是不好的做法之外,有没有一种方法可以运行单元测试来将代码运行到最后?
其中一个原因“一劳永逸”是一种不好的做法,即调用代码无法知道工作何时完成(或者它是否完成,或者它是否因错误而完成)。
正是这个原因使测试变得如此困难。您需要注入某种模拟来检测工作的任何副作用,并在测试中忙着等待,直到观察到副作用。超时将是必要的,以允许测试失败(而不是挂起),并且超时会使您的测试天生不稳定。这就是为什么“即发即弃”是一种不好的做法的原因之一。
【讨论】:
以上是关于如何对带有异步的流进行单元测试的主要内容,如果未能解决你的问题,请参考以下文章
如何对使用 Axios(或其他异步更新)的 Vue 组件进行单元测试?
对由 NSTimer 异步发送的 NSNotification 进行单元测试
使用 axios、TypeScript 模板和异步函数对 VueJS 进行单元测试