基本上我正在尝试制作作为HTTP请求结果的生成器,因此我经常以Gen[EitherT[Future, Error, T]]
这样的类型结束。
问题是似乎没有任何一元实例(所以我可以做sequence
,或单元变压器(让我组合不同的Gen[EitherT[Future, Error, T]]
实例
例如,假设我们有以下函数
def genUser: Gen[EitherT[Future, Error, User]]
和
def genAccounts(user: User): Gen[EitherT[Future, Error, List[Account]]
这个想法是能够正确地组合Gen[EitherT[Future, Error,T]
类型,以便genAccounts
调用genUser
,即类似
def genAccounts(user: User): Gen[EitherT[Future, Error, List[Account]] = for {
user <- genUser
accounts <- genAccounts(user)
} yield accounts
scalacheckGen
也提供了一种将Future
提升到Gen
的方法(即一种从Gen[Future[T]]
到仅Gen[T]
的方法(。即使这是阻塞,如果在我们生成最终Gen
属性时只发生一次,那也不是一个大问题
截至目前(2022 年底(,ScalaCheck 方面似乎没有对有效生成器的本机支持。有一个关于异步Prop
的问题。如问题中所述,该解决方案现在在库scalacheck效果中实现。
上述功能可能是一种解决方法,但需要嵌套异步属性而不是直接生成数据,例如
import org.scalacheck.Gen
import org.scalacheck.effect.PropF
import java.util.UUID
import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.duration.Duration
import scala.concurrent.{ Await, Future }
object TestAsync {
case class Box(uuid: UUID)
case class Wrapped(box: Box, name: Option[String])
val propF: PropF[Future] = PropF.forAllF(Gen.uuid) { uuid =>
Future(Box(uuid)).map { box =>
PropF.forAllF(Gen.alphaNumStr) { name =>
Future(Wrapped(box, Some(name))).map { wrapped =>
PropF.boolean[Future](wrapped.name.nonEmpty)
}
}
}
}
def main(args: Array[String]): Unit = {
Await.result(
propF
.check()
.map(println),
Duration.Inf
)
}
}
该用例仅用于演示,并且已经表明使用嵌套PropF
有些涉及。
另一种选择可能是使用ZIO,它处理的值与EitherT[Future, Error, A]
非常相似,并且具有有效的属性。