在几乎每个测试框架中,您都可以通过同步调用它来做到这一点
// given
val env: Environment[IO] = ...
val connector: DbConnector[IO] = DbConnector.impl[OP](env)
val url: DbUrl = ...
val user: DbUser = ...
val pw: DbPw = ...
// when
val result = connector.read(url, user, pw).attempt.unsafeRunSync
// then
val expected: DbParams = ...
assert(result == Right(expected))
由于 MUnit 本身也支持 Future,你也可以这样做:
// given
val env: Environment[IO] = ...
val connector: DbConnector[IO] = DbConnector.impl[OP](env)
val url: DbUrl = ...
val user: DbUser = ...
val pw: DbPw = ...
// when
connector.read(url, user, pw).attempt.unsafeToFuture.map { result =>
// then
val expected: DbParams = ...
assert(result == Right(expected))
}
您在那里的事实使您可以F
灵活地选择最容易测试的实现,每个测试:cats.effect.IO
, cats.effect.SyncIO
,monix.eval.Task
等。不同的测试框架仅在您如何在套件中组织测试方面有所不同,您可以使用什么样的匹配器使用并且有时与可用的集成,但您可以看到即使没有集成也能够编写测试。
如果您的代数的输出仅取决于输入,并且遵循某些合同,则每个实现都可以为它定义法律
class DbConnectorLaws[F[_]: MonadError[*[_], Throwable](
connector: DbConnector[F]
) {
// explicitly expressed contracts that tested class should fulfill
private def expectedReadOuput(dbUrl: DbUrl, user: DbUser, pw: DbPw) = ...
def nameOfReadContract(dbUrl: DbUrl, user: DbUser, pw: DbPw): F[Unit] =
connector.read(dbUrl, user, pw).map { result =>
// Cats laws has some utilities for making it prettier
assert(result == expectedReadOuput(dbUrl, user, pw))
}
}
然后您可以使用 Scalacheck 对其进行测试
import org.scalacheck.Arbitrary
import org.scalacheck.Prop.forAll
// actual test with laws (cats call them discipline)
trait DbConnectorTests {
val laws: DbConnectorLaws[IO] // simplified, study cats laws if you need it
def readContract()(
implicit
dbUrls: Arbitrary[DbUrl]
users: Arbitrary[DbUser]
pws: Arbitrary[DbPw]
// also other implicits if necessary
) = {
implicit val input = for {
url <- dbUrls
user <- users
pw <- pws
} yield (url, user, pw)
// simplified as well
forall { case (url: DbUrl, user: DbUser, pw: DbPw) =>
laws.nameOfReadContract(url, user, pw).unsafeRunSync // throws if assertion fail
}
}
}
val test = new DbConnectorTests { val laws = new DbConnectorLaws[IO](implementation) }
test.readContract()
但是,您的接口似乎依赖于实现并且独立于它自己,它不提供任何可以以这种方式测试的合约。我提到它只是因为您在其他问题中询问了“法律”。