ScalaCheck Effect is a library that extends the functionality of ScalaCheck to support "effectful" properties. An effectful property is one that evaluates each sample in some type constructor F[_]
. For example:
import org.scalacheck.effect.PropF
import org.scalacheck.Test
import cats.effect.{ExitCode, IO, IOApp}
object Example extends IOApp {
def run(args: List[String]): IO[ExitCode] = {
val p: PropF[IO] =
PropF.forAllF { (x: Int) =>
IO(x).map(res => assert(res == x))
}
val result: IO[Test.Result] = p.check()
result.flatMap(r => IO(println(r))).as(ExitCode.Success)
}
}
Running this program results in the output: Result(Passed,100,0,Map(),0)
.
This library provides the org.scalacheck.effect.PropF
type, which is the effectul analog to org.scalacheck.Prop
. In this example, we use PropF.forAllF
to write a property of the shape Int => IO[Unit]
. This example uses cats.effect.IO
as the type constructor, but any effect F[_]
with an instance of MonadError[F, Throwable]
can be used, including scala.concurrent.Future
.
The key idea here is using the PropF.{forAllF, forAllNoShrinkF}
methods to create PropF[F]
instances. The check()
method on PropF
converts a PropF[F]
to a F[Test.Result]
.
libraryDependencies += "org.typelevel" %% "scalacheck-effect" % scalacheckEffectVersion
This project also provides support for checking PropF
values from within MUnit based test suites. To use scalacheck-effect with munit, add the following dependency to your build:
libraryDependencies += "org.typelevel" %% "scalacheck-effect-munit" % scalacheckEffectVersion % Test
The following usage example is for Cats Effect 2:
import munit.{CatsEffectSuite, ScalaCheckEffectSuite}
import org.scalacheck.effect.PropF
// Example uses https://github.com/typelevel/munit-cats-effect
class ExampleSuite extends CatsEffectSuite with ScalaCheckEffectSuite {
test("first PropF test") {
PropF.forAllF { (x: Int) =>
IO(x).start.flatMap(_.join).map(res => assert(res == x))
}
}
}
For Cats Effect 3, the join
becomes joinWithNever
, so the PropF
in the above example becomes:
PropF.forAllF { (x: Int) =>
IO(x).start.flatMap(_.joinWithNever).map(res => assert(res == x))
}
For more details on the differences between Cats Effect 2 and 3 see the Cats Effect 3.x Migration Guide.
- Support effectful properties without blocking.
- Compatibility with
Gen
/Cogen
/Arbitrary
. - Parity with
Prop
features, including shrinking. - Follow same style as ScalaCheck and use ScalaCheck reporting.
- Integrate well with popular test frameworks.
- Non-goal: provide direct support for checking effectful properties directly from SBT or from standalone app.
Calling Await.result
, unsafeRunSync()
or a similar blocking operation is not possible on Scala.js.
By overriding the scalaCheckTestParameters
from the super ScalaCheckSuite
.
override def scalaCheckTestParameters =
super.scalaCheckTestParameters.withMinSuccessfulTests(20)
This library builds heavily on the ideas in ScalaCheck. It grew out of the FS2 AsyncPropertySuite
, which only implemented a handful of features. The Weaver Test framework also has similar support for effectful properties. Finally, the Scala Hedgehog library has a prototype of similar functionality.