Generators in ScalaCheck

Learn how to use and compose generators in ScalaCheck.

Automatic generators

We can unleash the full power of property-based testing with automatic generators. Different from table-driven property checking, generator-based tests can benefit from automatic generators of class instances. Normally, such an automatic generation tries to cover all the edge cases of our input domain.

We can’t generate input automatically with ScalaTest alone. In Scala the most popular property-based testing library is ScalaCheck. We’ll add it to our project (line 6).

Press + to interact
build.sbt
Dependencies.scala
object Dependencies {
object org {
object scalatestplus {
val `scalacheck-1-17` = "org.scalatestplus" %% "scalacheck-1-17" % "3.2.15.0"
}
}
}

In this lesson, we’ll see how we can leverage ScalaCheck to generate values for us.

Basic generation: the Properties class

The most basic form of property-based checking in ScalaCheck makes use of the Properties class. In this case, ScalaTest is not even necessary; we can write a property-based test suite simply by creating a Scala object (not a class—tests won’t run) extending ScalaCheck’s Properties.

We can start experimenting by writing a specification for the price of a FreeCourse, even though the logic we’ll be testing is trivial, to say the least.

package mdipirro.educative.io.effectiveunitandintegrationtestinginscala.properties

import mdipirro.educative.io.effectiveunitandintegrationtestinginscala.model.v3.{Author, FreeCourse, Lesson}
import org.scalacheck.Prop.propBoolean
import org.scalacheck.{Prop, Properties}

import scala.language.adhocExtensions

object FreeCoursePriceSpec extends Properties("A free course"):
  property("Is always free, no matter the number of lessons") = Prop `forAll` {
    (t: String, afn: String, aln: String, ts: Set[String]) =>
      (afn.nonEmpty && aln.nonEmpty) ==> {
        val lessons = ts map Lesson.apply
        val author = Author(afn, aln)

        FreeCourse(t, author, lessons, Set.empty).price == 0
      }
  }
Basic generator usage in ScalaCheck

As you can see, we defined an object extending the Properties class of the ScalaCheck library (line 9). The argument of the Properties constructor is the name of the unit under test. Note that we had to import scala.language.adhocExtensions (line 7). This is necessary because Properties is a class and it’s not declared open. Therefore, in Scala 3, we need that flag to extend it. ...