I have an interpreter for an algebra and I would like to write a unit test for it.
The interpreter is as follows:
final case class LiveDbConnector[F[_] : MonadError[*[_], Throwable]](env: Environment[F]) extends DbConnector[F] {
override def read(url: DbUrl, user: DbUser, pw: DbPw): F[DbParams] =
(for {
a <- OptionT(env.get(EnvVariable(url.v)))
b <- OptionT(env.get(EnvVariable(user.v)))
c <- OptionT(env.get(EnvVariable(pw.v)))
} yield DbParams(DbUrl(a.v), DbUser(b.v), DbPw(c.v)))
.value
.flatMap {
case Some(v) => v.pure[F]
case None => DbSettingError.raiseError[F, DbParams]
}
}
the algebra is as follows:
trait DbConnector[F[_]] {
def read(url: DbUrl, user: DbUser, pw: DbPw): F[DbParams]
}
the implementation is as follows:
final case class DbParams(url: DbUrl, user: DbUser, pw: DbPw)
object DbConnector {
def impl[F[_] : MonadError[*[_], Throwable]](env: Environment[F])
: DbConnector[F] =
new LiveDbConnector[F](env)
}
I use the test framework https://scalameta.org/munit/.
How to write unit test for my above algebra?
In virtually every test framework you could do this by calling this synchronously
Since MUnit also natively support Future, you could also do it like:
The fact that you have
Fthere gives you the flexibility of picking the implementation that is the easiest to test, per test:cats.effect.IO,cats.effect.SyncIO,monix.eval.Task, etc. And different test frameworks only differ in how you organize your tests in suites, what kind of matchers you can use and sometimes with available integrations, but you can see are able to write tests even without integrations.If every single implementation if your algebra had output depending only on input, and which would follow some contracts you could define laws for it
and then you could test it e.g with Scalacheck
However, is seems that your interface is implementation dependent and on its own, it doesn't provide any contracts that could be tested this way. I mention it only because in other questions you asked about "laws".