单元测试中异步/同步函数的使用差异及测试异步方法的最佳实践咨询
单元测试中异步/同步函数的使用差异及测试异步方法的最佳实践咨询
嘿,我特别理解你想在单元测试里精简冗余异步代码的需求——20个重复的async/await堆在一起确实挺烦人的。咱们一个个拆解你提到的几种写法的差异,帮你找到最靠谱的精简方案:
先明确核心原则:单元测试框架对异步代码的处理逻辑
所有主流.NET测试框架(xUnit、NUnit、MSTest)都只会等待返回Task/Task<T>的测试方法完成,而返回void的测试方法会被当成纯同步方法,框架不会等待任何内部的异步操作。这是所有问题的根源。
三种写法的逐一分析
1. 标准异步测试写法(最稳妥,语义清晰)
public async Task TestServiceError() { var client = GetMockClient("{RETURN}", HttpStatusCode.BadRequest); await Should.ThrowAsync<PreorderException>(async () => await client.Index()); }
这是官方推荐的标准写法:
- 测试方法标记
async Task,框架会自动等待所有异步操作完成 async () => await client.Index()是明确的异步委托,语义清晰,任何人看了都知道这里在等待异步操作- 完全不会有异步测试的坑,适合新手或者需要高可读性的场景
2. 返回void的同步测试写法(绝对不能用!)
public void TestServiceError() { var client = GetMockClient("{RETURN}", HttpStatusCode.BadRequest); Should.Throw<PreorderException>(async () => await client.Index()); }
这是踩坑重灾区:
- 测试方法返回
void,框架会直接执行完方法体就结束测试,完全不会等待内部的异步委托完成 - 异步委托里的异常可能在测试结束后才抛出,框架根本捕获不到,会变成未处理异常,甚至导致测试进程崩溃
- 偶尔会出现“测试通过但实际有问题”的幽灵失败,完全不可靠,别碰!
3. 返回Task的无async测试写法(最优精简方案)
public Task TestServiceError() { var client = GetMockClient("{RETURN}", HttpStatusCode.BadRequest); return Should.ThrowAsync<PreorderException>(() => client.Index()); }
这就是你要找的既精简又靠谱的写法!原因如下:
- 测试方法返回
Task,框架会自动等待这个Task完成,不需要加async/await(async只是语法糖,底层还是返回Task) Should.ThrowAsync本身就接受Func<Task>参数,而client.Index()直接返回Task<string>,所以直接传() => client.Index()就够了——FluentAssertions会自己等待这个Task完成,然后检查是否抛出了指定的异常- 完全去掉了冗余的
async/await,代码更简洁,同时完全避免了异步测试的坑
给你的最终建议
如果你有20个这样的测试,直接用第三种写法就好,甚至可以进一步抽离复用逻辑:
// 抽离复用的mock客户端创建逻辑 private MyApiClient GetErrorClient() => GetMockClient("{RETURN}", HttpStatusCode.BadRequest); // 精简后的测试用例 public Task TestServiceError_Index() => Should.ThrowAsync<PreorderException>(() => GetErrorClient().Index()); public Task TestServiceError_FindByODL() => Should.ThrowAsync<PreorderException>(() => GetErrorClient().FindByODLTest("order", "dealer", "lab")); public Task TestServiceError_Register() => Should.ThrowAsync<PreorderException>(() => GetErrorClient().RegisterAsync(new()));
这种写法既保证了测试的可靠性,又把冗余的async/await全部去掉,完全符合你的需求。
内容来源于stack exchange




