在我的单元测试应用程序中,我们的团队严重依赖工具来执行异步测试 - ConcurrencyExtras - withMainSerialExecutor
该工具增加了在主线程上启动测试代码的可能性,并且我们还可以添加await Task.yield()
块来等待某些耗时的操作完成
它运行良好,但看起来测试执行时间增加了,我想要缩短执行时间。
到目前为止,我发现的唯一解决方案是在这里建议添加
override func invokeTest() {
withMainSerialExecutor {
super.invokeTest()
}
}
在每个测试开始时,删除withMainSerialExecutor
所有地方。它起作用了,现在我的异步测试运行得更快了。
我的问题是 - 为什么它缩短了异步测试的执行时间?我所做的基本上是强制每个测试在主线程上执行,但手动添加的withMainSerialExecutor
块也做了同样的事情。也许有人有其他解决方案来缩短异步测试的执行时间?
从“长”区域(超过 0.1 秒)移至短的测试示例
func testHasLoaded() async {
/// Arrange
sut = makeVM()
var hasLoaded = String()
sut.dataHasFinishedLoading = {
hasLoaded = "hasLoaded"
}
/// Assert
await Task.megaYield()
XCTAssertEqual(hasLoaded, "hasLoaded")
}
原始(0.11秒):
func testHasLoaded() async {
withMainSerialExecutor {
/// Arrange
sut = makeVM()
var hasLoaded = String()
sut.dataHasFinishedLoading = {
hasLoaded = "hasLoaded"
}
/// Assert
await Task.megaYield()
XCTAssertEqual(hasLoaded, "hasLoaded")
}
}
我可能认为收益(或者更糟的是“超级收益”)是一种反模式。
测试支持 Swift 并发,所以我会
await
调用你的dataHasFinishedLoading
闭包。我们可以通过将它包装在延续中来实现这一点。有很多方法可以做到这一点,但也许一个AsyncStream
:仅供参考,您在评论中说:
期望不会显著增加测试运行时间。这是 Stack Overflow 上经常重复的错误说法。如果出现错误并且期望未在合理的时间范围内得到满足,则超时是最糟糕的情况。但如果期望及时得到满足,则期望会立即完成,不会等待超时。
现在,如果您不喜欢以秒为单位的故障安全超时,那么,好吧,为这种“异步工作无法及时完成”的情况设置一个更短的超时。也许将超时设置为以几十或几百毫秒而不是秒为单位。但您的“超级收益”做了完全相同的事情:它增加了延迟。当然,这种等待可能不是以秒为单位的(我们不能在没有看到您的
megaYield
实现的情况下说),但它仍然在等待。这种收益工作流程实际上可能更糟糕,因为无论异步工作何时实际完成,它都会插入延迟。您总是只希望超时来应对最坏的情况,但在成功的情况下,立即完成。您永远不希望测试等待的时间超过需要的时间。这就是期望所实现的。这也是上述
async
模式await
所实现的。但添加一堆收益或任何固定延迟是朝着错误方向迈出的一步。我对期望的批评仅限于这样一个事实:它们是传统 XCTest 模式的产物,但在新的Swift 测试框架中不可用。这个新的测试框架使用
async
-await
模式(这就是我在上面使用该模式的原因)。出于这个原因,人们可能希望避免在此时引入期望,以尽量减少最终迁移到较新的 Swift 测试框架时所需的返工量。