【发布时间】:2020-07-30 14:51:01
【问题描述】:
假设我有这个方法:
def callApis(f1, f2, f3):Future[Result] {
for {
a <- Future { f1 }
b <- Future { f2 }
c <- Future { f3 }
} yield Result(a,b,c)
}
如果您熟悉 scala,您就会知道 for 块中的行将按顺序执行。更具体地说,将首先计算 a。然后当我们得到 a 的结果时,代码将计算 b。然后当我们得到b的结果时,代码将计算c。
我的问题是,如何编写一个单元测试来确保始终在计算 b 之前计算 a,并且始终在计算 c 之前计算 b? 我担心如果有人不知道很多关于期货如何在scala中工作的信息。他们可能会不小心使此代码异步运行。
我的意思是人们可能不小心做这样的事情,这使得 a,b,c 被异步计算(我不希望人们这样做):
def callApis(f1, f2, f3):Future[Result] {
val fut1 = Future { f1 }
val fut2 = Future { f2 }
val fut3 = Future { f3 }
for {
a <- fut1
b <- fut2
c <- fut3
} yield Result(a,b,c)
}
【问题讨论】:
-
如果在第一个任务完成之前提交第二个任务,则使用失败的执行上下文对其进行测试。如果期货启动更多期货,那么记账就更难了,您应该使用诸如倒计时锁存器之类的显式协调,并让他们根据需要使用第二种语法。
-
@som-snytt 我理解你的决心。但是如果第二个任务在第一个任务完成后提交,我们不能确定代码是否按顺序运行。我的意思是我们只能确定第一个任务完成后第二个任务何时开始。我不知道如何检查。
-
我想这不是一个解决方案,因为你需要Future,但如果没有这样的限制,我建议使用任何现有的IO而不是Future(例如Cats Effect)。这将为您提供开箱即用的保证,因此您无需进行测试。
-
@highDopamine 除了您已经收到的有价值的 cmets 和答案之外,我想指出,测试来自您使用的库的设计决策的行为感觉有点奇怪我。这就像在你告诉 mockito 返回一些值时测试它是否真的返回一些值。如果您对 Futures 的这种行为方式有疑问(我很高兴您认识到了这一点),那么投资于猫 IO、Monix Task 或 ZIO 等效果类型怎么样?我知道不是每个项目都能负担得起,但也许你的可以。
标签: scala unit-testing asynchronous future