From a8eae1472ac5f38acff9ce8fed15217e9736e14a Mon Sep 17 00:00:00 2001 From: "Kai(luo) Wang" Date: Fri, 4 May 2018 16:28:30 -0400 Subject: [PATCH 01/10] clarify law testing's dependency on cats-testkit and scalatest --- docs/src/main/tut/typeclasses/lawtesting.md | 23 +++++++++++++-------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/docs/src/main/tut/typeclasses/lawtesting.md b/docs/src/main/tut/typeclasses/lawtesting.md index f92e1fb676..9627a3210b 100644 --- a/docs/src/main/tut/typeclasses/lawtesting.md +++ b/docs/src/main/tut/typeclasses/lawtesting.md @@ -7,23 +7,25 @@ section: "typeclasses" # Law testing [Laws](https://typelevel.org/cats/typeclasses.html#laws) are an important part of cats. -Cats uses `catalysts` and `discipline` to help test instances with laws. -To make things easier, cats ships with `cats-testkit`, which makes use of `catalysts` and `discipline` and exposes `CatsSuite` based on ScalaTest. +Cats uses `catalysts` and [discipline](https://github.com/typelevel/discipline) to help test instances with laws. To test type class +laws from Cats against your instances, you need to add a `cats-laws` dependency. +If you are using `ScalaTests`, Cats also ships with `cats-testkit`, which exposes `CatsSuite` based on ScalaTest. ## Getting started -First up, you will need to specify dependencies on `cats-laws` and `cats-testkit` in your `build.sbt` file. +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`. ```scala libraryDependencies ++= Seq( - "org.typelevel" %% "cats-laws" % "1.0.1" % Test, - "org.typelevel" %% "cats-testkit" % "1.0.1"% Test, + "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. @@ -50,8 +52,8 @@ For simplicity we'll just use `Eq.fromUniversalEquals`: implicit def eqTree[A: Eq]: Eq[Tree[A]] = Eq.fromUniversalEquals ``` -Then we can begin to write our law tests. Start by creating a new class in your `test` folder and inheriting from `cats.tests.CatsSuite`. -`CatsSuite` extends the standard ScalaTest `FunSuite` as well as `Matchers`. +Then we can begin to write our law tests. If you are using `ScalaTest` you can inherit from `cats.tests.CatsSuite` +from `cats-testkit`. `CatsSuite` extends the standard ScalaTest `FunSuite` as well as `Matchers`. Furthermore it also pulls in all of cats instances and syntax, so there's no need to import from `cats.implicits._`. ```tut:book @@ -62,8 +64,11 @@ class TreeLawTests extends CatsSuite { } ``` -The key to testing laws is the `checkAll` function, which takes a name for your test and a Discipline ruleset. -Cats has defined rulesets for all type class laws in `cats.laws.discipline.*`. +The key to testing laws is the `checkAll` function provided by [discipline](https://github.com/typelevel/discipline), +which takes a name for your test and a Discipline ruleset. +Cats has defined rulesets for all type class laws in `cats.laws.discipline.*`. As of now, [discipline](https://github.com/typelevel/discipline) provides this helper `checkAll` only for `ScalaTest` and `Spec2`, +but it should not be hard for you to write your own `checkAll` for your test framework of choice following this +[example](https://github.com/typelevel/discipline/blob/master/shared/src/main/scala/scalatest/Discipline.scala). So for our example we will want to import `cats.laws.discipline.FunctorTests` and call `checkAll` with it. Before we do so, however, From 6889139d8cb4da33efa3274937a4c0f764b05193 Mon Sep 17 00:00:00 2001 From: "Kai(luo) Wang" Date: Fri, 4 May 2018 16:29:16 -0400 Subject: [PATCH 02/10] Update lawtesting.md --- docs/src/main/tut/typeclasses/lawtesting.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/src/main/tut/typeclasses/lawtesting.md b/docs/src/main/tut/typeclasses/lawtesting.md index 9627a3210b..ecfc6b5656 100644 --- a/docs/src/main/tut/typeclasses/lawtesting.md +++ b/docs/src/main/tut/typeclasses/lawtesting.md @@ -15,7 +15,7 @@ If you are using `ScalaTests`, Cats also ships with `cats-testkit`, which expose ## 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`(. +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`. ```scala From 5dca10815620f5c4749a910cc1211790e70f7390 Mon Sep 17 00:00:00 2001 From: "Kai(luo) Wang" Date: Mon, 7 May 2018 17:05:04 -0400 Subject: [PATCH 03/10] Update lawtesting.md --- docs/src/main/tut/typeclasses/lawtesting.md | 66 ++++++++++++--------- 1 file changed, 38 insertions(+), 28 deletions(-) diff --git a/docs/src/main/tut/typeclasses/lawtesting.md b/docs/src/main/tut/typeclasses/lawtesting.md index ecfc6b5656..9f1340a99b 100644 --- a/docs/src/main/tut/typeclasses/lawtesting.md +++ b/docs/src/main/tut/typeclasses/lawtesting.md @@ -7,9 +7,12 @@ section: "typeclasses" # Law testing [Laws](https://typelevel.org/cats/typeclasses.html#laws) are an important part of cats. -Cats uses `catalysts` and [discipline](https://github.com/typelevel/discipline) to help test instances with laws. To test type class -laws from Cats against your instances, you need to add a `cats-laws` dependency. -If you are using `ScalaTests`, Cats also ships with `cats-testkit`, which exposes `CatsSuite` based on ScalaTest. +Cats uses [discipline](https://github.com/typelevel/discipline) to define type class laws and +the [ScalaCheck](https://github.com/rickynils/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 `ScalaTests`, Cats also ships with optional `cats-testkit`, which provites a convenient +base test class `CatsSuite`. ## Getting started @@ -45,37 +48,23 @@ object Tree { } } ``` -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`: -```tut:book -implicit def eqTree[A: Eq]: Eq[Tree[A]] = Eq.fromUniversalEquals +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 +```tut: silent +cats.laws.discipline.FunctorTests[Tree].functor[Int, Int, String].all ``` -Then we can begin to write our law tests. If you are using `ScalaTest` you can inherit from `cats.tests.CatsSuite` -from `cats-testkit`. `CatsSuite` extends the standard ScalaTest `FunSuite` as well as `Matchers`. -Furthermore it also pulls in all of cats instances and syntax, so there's no need to import from `cats.implicits._`. +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`: ```tut:book -import cats.tests.CatsSuite - -class TreeLawTests extends CatsSuite { - -} +implicit def eqTree[A: Eq]: Eq[Tree[A]] = Eq.fromUniversalEquals ``` - -The key to testing laws is the `checkAll` function provided by [discipline](https://github.com/typelevel/discipline), -which takes a name for your test and a Discipline ruleset. -Cats has defined rulesets for all type class laws in `cats.laws.discipline.*`. As of now, [discipline](https://github.com/typelevel/discipline) provides this helper `checkAll` only for `ScalaTest` and `Spec2`, -but it should not be hard for you to write your own `checkAll` for your test framework of choice following this -[example](https://github.com/typelevel/discipline/blob/master/shared/src/main/scala/scalatest/Discipline.scala). - -So for our example we will want to import `cats.laws.discipline.FunctorTests` and call `checkAll` with it. -Before we do so, however, -we will have to bring our instances into scope as well as the derived `Arbitrary` instances from `scalacheck-shapeless` -(We have defined an Arbitrary instance for `Tree` here, but you won't need it if you import `org.scalacheck.ScalacheckShapeless._`). - - +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._`). ```tut:silent @@ -88,6 +77,27 @@ implicit def arbFoo[A: Arbitrary]: Arbitrary[Tree[A]] = ) ``` + +Now we can convert these `ScalaCheck` `Properties` into tests that the test framework can run. + +[discipline](https://github.com/typelevel/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. + ```tut:book import Tree._ From b63abdf0d2dad25d235a3415677dd7cbf68025b8 Mon Sep 17 00:00:00 2001 From: "Kai(luo) Wang" Date: Mon, 7 May 2018 17:06:47 -0400 Subject: [PATCH 04/10] Update lawtesting.md --- docs/src/main/tut/typeclasses/lawtesting.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/src/main/tut/typeclasses/lawtesting.md b/docs/src/main/tut/typeclasses/lawtesting.md index 9f1340a99b..b30950e82a 100644 --- a/docs/src/main/tut/typeclasses/lawtesting.md +++ b/docs/src/main/tut/typeclasses/lawtesting.md @@ -100,7 +100,7 @@ call the `checkAll` helper with it. ```tut:book import Tree._ - +import cats.tests.CatsSuite import cats.laws.discipline.FunctorTests class TreeLawTests extends CatsSuite { From 33112715e9d8547ab9461cbed51e2658338693c1 Mon Sep 17 00:00:00 2001 From: "Kai(luo) Wang" Date: Mon, 7 May 2018 17:07:55 -0400 Subject: [PATCH 05/10] Update lawtesting.md --- docs/src/main/tut/typeclasses/lawtesting.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/src/main/tut/typeclasses/lawtesting.md b/docs/src/main/tut/typeclasses/lawtesting.md index b30950e82a..c249c48cd0 100644 --- a/docs/src/main/tut/typeclasses/lawtesting.md +++ b/docs/src/main/tut/typeclasses/lawtesting.md @@ -53,7 +53,7 @@ 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 -```tut: silent +```tut:book cats.laws.discipline.FunctorTests[Tree].functor[Int, Int, String].all ``` From 329e5aeca72ec7edcab7967ee4931ce8e211f40d Mon Sep 17 00:00:00 2001 From: "Kai(luo) Wang" Date: Tue, 8 May 2018 10:43:36 -0400 Subject: [PATCH 06/10] fixing tut compilation --- docs/src/main/tut/typeclasses/lawtesting.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/src/main/tut/typeclasses/lawtesting.md b/docs/src/main/tut/typeclasses/lawtesting.md index c249c48cd0..3514bfcb52 100644 --- a/docs/src/main/tut/typeclasses/lawtesting.md +++ b/docs/src/main/tut/typeclasses/lawtesting.md @@ -53,6 +53,9 @@ 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 +```tut:invisible +import Tree._ //there is no real companion object is in REPL +``` ```tut:book cats.laws.discipline.FunctorTests[Tree].functor[Int, Int, String].all ``` From a534ceeceba3d2b2032d8bfe37c28423306bb3c7 Mon Sep 17 00:00:00 2001 From: "Kai(luo) Wang" Date: Tue, 8 May 2018 11:27:14 -0400 Subject: [PATCH 07/10] Update lawtesting.md --- docs/src/main/tut/typeclasses/lawtesting.md | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/docs/src/main/tut/typeclasses/lawtesting.md b/docs/src/main/tut/typeclasses/lawtesting.md index 3514bfcb52..cbe31493d6 100644 --- a/docs/src/main/tut/typeclasses/lawtesting.md +++ b/docs/src/main/tut/typeclasses/lawtesting.md @@ -48,15 +48,16 @@ object Tree { } } ``` +```tut:invisible +import Tree._ //there is no real companion object is in REPL +``` 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 -```tut:invisible -import Tree._ //there is no real companion object is in REPL -``` -```tut:book + +```scala cats.laws.discipline.FunctorTests[Tree].functor[Int, Int, String].all ``` From 8e5e75855c8e52223f7d5b2215bd9d8e8821eac8 Mon Sep 17 00:00:00 2001 From: "Kai(luo) Wang" Date: Wed, 9 May 2018 07:05:33 -0400 Subject: [PATCH 08/10] Update lawtesting.md --- docs/src/main/tut/typeclasses/lawtesting.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/src/main/tut/typeclasses/lawtesting.md b/docs/src/main/tut/typeclasses/lawtesting.md index cbe31493d6..c6fe822d29 100644 --- a/docs/src/main/tut/typeclasses/lawtesting.md +++ b/docs/src/main/tut/typeclasses/lawtesting.md @@ -11,7 +11,7 @@ Cats uses [discipline](https://github.com/typelevel/discipline) to define type c the [ScalaCheck](https://github.com/rickynils/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 `ScalaTests`, Cats also ships with optional `cats-testkit`, which provites a convenient +If you are using `ScalaTest`, Cats also ships with optional `cats-testkit`, which provites a convenient base test class `CatsSuite`. From 7e2f9de3e523e4dad6530faef8220516dc0897bc Mon Sep 17 00:00:00 2001 From: "Kai(luo) Wang" Date: Wed, 9 May 2018 11:45:34 -0400 Subject: [PATCH 09/10] Update lawtesting.md --- docs/src/main/tut/typeclasses/lawtesting.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/src/main/tut/typeclasses/lawtesting.md b/docs/src/main/tut/typeclasses/lawtesting.md index c6fe822d29..9224cb3cb0 100644 --- a/docs/src/main/tut/typeclasses/lawtesting.md +++ b/docs/src/main/tut/typeclasses/lawtesting.md @@ -49,7 +49,7 @@ object Tree { } ``` ```tut:invisible -import Tree._ //there is no real companion object is in REPL +import Tree._ //there is no real companion object in REPL ``` Cats defines all type class laws tests in `cats.laws.discipline.*` From fd77b9c41dd624f9dbd3277ca080f7e1627bbbd3 Mon Sep 17 00:00:00 2001 From: "Kai(luo) Wang" Date: Wed, 9 May 2018 11:46:23 -0400 Subject: [PATCH 10/10] Update lawtesting.md --- docs/src/main/tut/typeclasses/lawtesting.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/src/main/tut/typeclasses/lawtesting.md b/docs/src/main/tut/typeclasses/lawtesting.md index 9224cb3cb0..9901bd6021 100644 --- a/docs/src/main/tut/typeclasses/lawtesting.md +++ b/docs/src/main/tut/typeclasses/lawtesting.md @@ -103,7 +103,7 @@ So here is the Scalatest test for our example, basically we import `cats.laws.di call the `checkAll` helper with it. ```tut:book -import Tree._ + import cats.tests.CatsSuite import cats.laws.discipline.FunctorTests