# Law testing

Laws are an important part of cats. Cats uses discipline to define type class laws and the ScalaCheck tests based on them.

To test type class laws from Cats against your instances, you need to add a `cats-laws`

dependency.
If you are using `ScalaTest`

, Cats also ships with optional `cats-testkit`

, which provites a convenient
base test class `CatsSuite`

.

## Getting started

First up, you will need to specify dependencies on `cats-laws`

in your `build.sbt`

file (or `cats-testkit`

if you
are using `ScalaTest`

).
To make things easier, we’ll also include the `scalacheck-shapeless`

library in this tutorial, so we don’t have to manually write instances for ScalaCheck’s `Arbitrary`

.

```
libraryDependencies ++= Seq(
"org.typelevel" %% "cats-laws" % "1.1.0" % Test, //or `cats-testkit` if you are using ScalaTest
"com.github.alexarchambault" %% "scalacheck-shapeless_1.13" % "1.1.6" % Test
)
```

## Example: Testing a Functor instance

We’ll begin by creating a data type and its Functor instance.

```
import cats._
// import cats._
sealed trait Tree[+A]
// defined trait Tree
case object Leaf extends Tree[Nothing]
// defined object Leaf
case class Node[A](p: A, left: Tree[A], right: Tree[A]) extends Tree[A]
// defined class Node
object Tree {
implicit val functorTree: Functor[Tree] = new Functor[Tree] {
def map[A, B](tree: Tree[A])(f: A => B) = tree match {
case Leaf => Leaf
case Node(p, left, right) => Node(f(p), map(left)(f), map(right)(f))
}
}
}
// defined object Tree
// warning: previously defined trait Tree is not a companion to object Tree.
// Companions must be defined together; you may wish to use :paste mode for this.
```

Cats defines all type class laws tests in `cats.laws.discipline.*`

as `discipline`

’s `RuleSet`

s. Each `RuleSet`

provides a `ScalaCheck`

`Properties`

through
`ruleSet.all`

to represent all the rules that it defines and inherits. For example,
the `ScalaCheck`

`Properties`

for `Functor`

can be retrieved using

```
cats.laws.discipline.FunctorTests[Tree].functor[Int, Int, String].all
```

We will also need to create an `Eq`

instance, as most laws will need to compare values of a type to properly test for correctness.
For simplicity we’ll just use `Eq.fromUniversalEquals`

:

```
implicit def eqTree[A: Eq]: Eq[Tree[A]] = Eq.fromUniversalEquals
// eqTree: [A](implicit evidence$1: cats.Eq[A])cats.Eq[Tree[A]]
```

ScalaCheck requires `Arbitrary`

instances for data types being tested. We have defined an `Arbitrary`

instance for `Tree`

here,
but you won’t need it if you import `org.scalacheck.ScalacheckShapeless._`

).

```
import org.scalacheck.{Arbitrary, Gen}
implicit def arbFoo[A: Arbitrary]: Arbitrary[Tree[A]] =
Arbitrary(Gen.oneOf(Gen.const(Leaf), (for {
e <- Arbitrary.arbitrary[A]
} yield Node(e, Leaf, Leaf)))
)
```

Now we can convert these `ScalaCheck`

`Properties`

into tests that the test framework can run.

discipline provides two helper `checkAll`

functions that perform
this conversion for two test frameworks: `ScalaTest`

and `Spec2`

.

If you are using `Specs2`

, let the test class extend `org.typelevel.discipline.specs2.Discipline`

which provides the `checkAll`

function.

If you are using `ScalaTest`

, let the test class extend `org.typelevel.discipline.scalatest.Discipline`

, or
inherit from the more convenient `cats.tests.CatsSuite`

from `cats-testkit`

.
`CatsSuite`

extends the standard ScalaTest `FunSuite`

, `Matchers`

together with
`org.typelevel.discipline.scalatest.Discipline`

. Furthermore it also pulls in all of cats instances and syntax,
so there’s no need to import from `cats.implicits._`

.

For other test frameworks, you need to resort to their integration with `ScalaCheck`

to test
the `ScalaCheck`

`Properties`

provided by cats-laws.

So here is the Scalatest test for our example, basically we import `cats.laws.discipline.FunctorTests`

and
call the `checkAll`

helper with it.

```
import cats.tests.CatsSuite
// import cats.tests.CatsSuite
import cats.laws.discipline.FunctorTests
// import cats.laws.discipline.FunctorTests
class TreeLawTests extends CatsSuite {
checkAll("Tree.FunctorLaws", FunctorTests[Tree].functor[Int, Int, String])
}
// defined class TreeLawTests
```

Now when we run `test`

in our sbt console, ScalaCheck will test if the `Functor`

laws hold for our `Tree`

type.
You should see something like this:

```
[info] TreeLawTests:
[info] - Tree.FunctorLaws.functor.covariant composition
[info] - Tree.FunctorLaws.functor.covariant identity
[info] - Tree.FunctorLaws.functor.invariant composition
[info] - Tree.FunctorLaws.functor.invariant identity
[info] ScalaTest
[info] Run completed in 537 milliseconds.
[info] Total number of tests run: 4
[info] Suites: completed 1, aborted 0
[info] Tests: succeeded 4, failed 0, canceled 0, ignored 0, pending 0
[info] All tests passed.
[info] Passed: Total 4, Failed 0, Errors 0, Passed 4
[success] Total time: 1 s, completed Aug 31, 2017 2:19:22 PM
```

And voila, you’ve successfully proven that your data type upholds the Functor laws!

### Testing cats.kernel instances

For most of the type classes included in cats, the above will work great.
However, the law tests for the type classes inside `cats.kernel`

are located in `cats.kernel.laws.discipline.*`

instead.
So we have to import from there to test type classes like `Semigroup`

, `Monoid`

, `Group`

or `Semilattice`

.

Let’s test it out, by defining a `Semigroup`

instance for our `Tree`

type.

```
import cats.implicits._
// import cats.implicits._
implicit def semigroupTree[A: Semigroup]: Semigroup[Tree[A]] = new Semigroup[Tree[A]] {
def combine(x: Tree[A], y: Tree[A]) = (x, y) match {
case (Leaf, _) => Leaf
case (_, Leaf) => Leaf
case (Node(xp, xLeft, xRight), Node(yp, yLeft, yRight)) =>
Node(xp |+| yp, xLeft |+| yLeft, xRight |+| yRight)
}
}
// semigroupTree: [A](implicit evidence$1: cats.Semigroup[A])cats.Semigroup[Tree[A]]
```

Then we can again test the instance inside our class extending `CatsSuite`

:

```
import cats.laws.discipline.FunctorTests
// import cats.laws.discipline.FunctorTests
import cats.kernel.laws.discipline.SemigroupTests
// import cats.kernel.laws.discipline.SemigroupTests
class TreeLawTests extends CatsSuite {
checkAll("Tree[Int].SemigroupLaws", SemigroupTests[Tree[Int]].semigroup)
checkAll("Tree.FunctorLaws", FunctorTests[Tree].functor[Int, Int, String])
}
// defined class TreeLawTests
```