Skip to content

Commit

Permalink
Merge pull request #1233 from Kazark/munit
Browse files Browse the repository at this point in the history
Add doobie-munit package to integrate Doobie with the shiny new MUnit
  • Loading branch information
jatcwang committed May 23, 2021
2 parents e865389 + 176a5a1 commit a8021d1
Show file tree
Hide file tree
Showing 6 changed files with 158 additions and 3 deletions.
20 changes: 19 additions & 1 deletion build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ lazy val postgresVersion = "42.2.20"
lazy val refinedVersion = "0.9.25"
lazy val scalaCheckVersion = "1.15.4"
lazy val scalatestVersion = "3.2.9"
lazy val munitVersion = "0.7.26"
lazy val shapelessVersion = "2.3.7"
lazy val silencerVersion = "1.7.1"
lazy val specs2Version = "4.11.0"
Expand Down Expand Up @@ -168,6 +169,7 @@ lazy val doobie = project.in(file("."))
quill,
refined,
scalatest,
munit,
specs2,
)

Expand Down Expand Up @@ -397,6 +399,22 @@ lazy val scalatest = project
)
.settings(noDottySettings)

lazy val munit = project
.in(file("modules/munit"))
.enablePlugins(AutomateHeaderPlugin)
.dependsOn(core)
.settings(doobieSettings)
.settings(publishSettings)
.settings(
name := s"doobie-munit",
description := "MUnit support for doobie.",
testFrameworks += new TestFramework("munit.Framework"),
libraryDependencies ++= Seq(
"org.scalameta" %% "munit" % munitVersion,
"com.h2database" % "h2" % h2Version % "test"
)
)

lazy val bench = project
.in(file("modules/bench"))
.enablePlugins(AutomateHeaderPlugin)
Expand All @@ -407,7 +425,7 @@ lazy val bench = project

lazy val docs = project
.in(file("modules/docs"))
.dependsOn(core, postgres, specs2, hikari, h2, scalatest, quill)
.dependsOn(core, postgres, specs2, munit, hikari, h2, scalatest, quill)
.enablePlugins(ParadoxPlugin)
.enablePlugins(ParadoxSitePlugin)
.enablePlugins(GhpagesPlugin)
Expand Down
2 changes: 1 addition & 1 deletion modules/docs/src/main/mdoc/docs/06-Checking.md
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ def biggerThan2(minPop: Int) =
biggerThan2(0).check.unsafeRunSync()
```

**doobie** supports `check` for queries and updates in three ways: programmatically, via YOLO mode in the REPL, and via the `doobie-specs2` and `doobie-scalatest` packages, which allow checking to become part of your unit test suite. We will investigate this in the chapter on testing.
**doobie** supports `check` for queries and updates in four ways: programmatically, via YOLO mode in the REPL, and via the `doobie-specs2`, `doobie-scalatest` and `doobie-munit` packages, which allow checking to become part of your unit test suite. We will investigate this in the chapter on testing.

### Working Around Bad Metadata

Expand Down
24 changes: 23 additions & 1 deletion modules/docs/src/main/mdoc/docs/13-Unit-Testing.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
## Unit Testing

The YOLO-mode query checking feature demonstated in an earlier chapter is also available as a trait you can mix into your [Specs2](http://etorreborre.github.io/specs2/) or [ScalaTest](http://www.scalatest.org/) unit tests.
The YOLO-mode query checking feature demonstated in an earlier chapter is also available as a trait you can mix into your [Specs2](http://etorreborre.github.io/specs2/), [ScalaTest](http://www.scalatest.org/) or [MUnit](https://scalameta.org/munit) unit tests.

### Setting Up

Expand Down Expand Up @@ -129,3 +129,25 @@ Details are shown for failing tests.
// Run a test programmatically. Usually you would do this from sbt, bloop, etc.
(new AnalysisTestScalaCheck).execute(color = false)
```

### The MUnit Package

The `doobie-munit` add-on provides a mix-in trait that we can add to any `Assertions` implementation (like `FunSuite`) much like the ScalaTest package above.

```scala mdoc:silent
import _root_.munit._

class AnalysisTestSuite extends FunSuite with doobie.munit.IOChecker {

override val colors = doobie.util.Colors.None // just for docs

val transactor = Transactor.fromDriverManager[IO](
"org.postgresql.Driver", "jdbc:postgresql:world", "postgres", ""
)

test("trivial") { check(trivial) }
test("biggerThan") { check(biggerThan(0)) }
test("update") { check(update("", "")) }

}
```
67 changes: 67 additions & 0 deletions modules/munit/src/main/scala/doobie/munit/analysisspec.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
// Copyright (c) 2013-2020 Rob Norris and Contributors
// This software is licensed under the MIT License (MIT).
// For more information see LICENSE or https://opensource.org/licenses/MIT

package doobie.munit

import cats.effect.{ Effect, IO }
import doobie.util.query.{Query, Query0}
import doobie.util.testing._
import org.tpolecat.typename._
import munit.Assertions
import munit.Location

/**
* Module with a mix-in trait for specifications that enables checking of doobie `Query` and `Update` values.
*
* {{{
* class ExampleSuite extends FunSuite with IOChecker {
*
* // The transactor to use for the tests.
* val transactor = Transactor.fromDriverManager[IO](
* "org.postgresql.Driver",
* "jdbc:postgresql:world",
* "postgres", ""
* )
*
* // Now just mention the queries. Arguments are not used.
* test("findByNameAndAge") { check(MyDaoModule.findByNameAndAge(null, 0)) }
* test("allWoozles") { check(MyDaoModule.allWoozles) }
*
* }
* }}}
*/
object analysisspec {

trait Checker[M[_]] extends CheckerBase[M] { this: Assertions =>

def check[A: Analyzable](a: A)(implicit loc: Location) = checkImpl(Analyzable.unpack(a))

def checkOutput[A: TypeName](q: Query0[A])(implicit loc: Location) =
checkImpl(AnalysisArgs(
s"Query0[${typeName[A]}]", q.pos, q.sql, q.outputAnalysis
))

def checkOutput[A: TypeName, B: TypeName](q: Query[A, B])(implicit loc: Location) =
checkImpl(AnalysisArgs(
s"Query[${typeName[A]}, ${typeName[B]}]", q.pos, q.sql, q.outputAnalysis
))

private def checkImpl(args: AnalysisArgs)(implicit loc: Location) = {
val report = analyzeIO(args, transactor).unsafeRunSync()
if (!report.succeeded) {
fail(
formatReport(args, report, colors)
.padLeft(" ")
.toString
)
}
}
}

/** Implementation of Checker[IO] */
trait IOChecker extends Checker[IO] {
self: Assertions =>
val M: Effect[IO] = implicitly
}
}
12 changes: 12 additions & 0 deletions modules/munit/src/main/scala/doobie/munit/package.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
// Copyright (c) 2013-2020 Rob Norris and Contributors
// This software is licensed under the MIT License (MIT).
// For more information see LICENSE or https://opensource.org/licenses/MIT

package doobie

package object munit {

type Checker[M[_]] = analysisspec.Checker[M]
type IOChecker = analysisspec.IOChecker

}
36 changes: 36 additions & 0 deletions modules/munit/src/test/scala/doobie/munit/CheckerTests.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
// Copyright (c) 2013-2020 Rob Norris and Contributors
// This software is licensed under the MIT License (MIT).
// For more information see LICENSE or https://opensource.org/licenses/MIT

package doobie.munit

import cats.effect.{ ContextShift, IO }
import doobie.syntax.string._
import doobie.util.transactor.Transactor
import munit._
import scala.concurrent.ExecutionContext

trait CheckerChecks[M[_]] extends FunSuite with Checker[M] {

implicit def contextShift: ContextShift[M]

lazy val transactor = Transactor.fromDriverManager[M](
"org.h2.Driver",
"jdbc:h2:mem:queryspec;DB_CLOSE_DELAY=-1",
"sa", ""
)

test("trivial") { check(sql"select 1".query[Int]) }

test("fail".fail) { check(sql"select 1".query[String]) }

final case class Foo[F[_]](x: Int)

test ("trivial case-class"){ check(sql"select 1".query[Foo[cats.Id]]) }

}

class IOCheckerCheck extends CheckerChecks[IO] with IOChecker {
def contextShift: ContextShift[IO] =
IO.contextShift(ExecutionContext.global)
}

0 comments on commit a8021d1

Please sign in to comment.