MUnit

MUnit

  • Docs
  • Blog
  • GitHub

›Overview

Overview

  • Getting started
  • Declaring tests
  • Writing assertions
  • Using fixtures
  • Filtering tests
  • Coming from ScalaTest
  • Troubleshooting

Integrations

  • ScalaCheck
  • External Integrations
Edit

Writing assertions

MUnit provides a few ways to fail a test given a condition.

assert()

Use assert() to fail a test if a boolean condition does not hold true. For example, assume we have two values:

val a = 1
// a: Int = 1
val b = 2
// b: Int = 2

In the most basic case when no hints are provided, the error message is "assertion failed" when the condition is false.

assert(a > b)
// munit.FailException: assertion failed
//  at munit.Assertions.fail(Assertions.scala:274)
//  at munit.Assertions.fail$(Assertions.scala:269)
//  at munit.FunSuite.fail(FunSuite.scala:13)
//  at munit.Assertions.$anonfun$assert$1(Assertions.scala:36)
//  at scala.runtime.java8.JFunction0$mcV$sp.apply(JFunction0$mcV$sp.scala:18)
//  at munit.internal.console.StackTraces$.dropInside(StackTraces.scala:10)
//  at munit.Assertions.assert(Assertions.scala:34)
//  at munit.Assertions.assert$(Assertions.scala:32)
//  at munit.FunSuite.assert(FunSuite.scala:13)
//  at repl.MdocSession$MdocApp$$anonfun$1.apply$mcV$sp(assertions.md:29)
//  at repl.MdocSession$MdocApp$$anonfun$1.apply(assertions.md:29)
//  at repl.MdocSession$MdocApp$$anonfun$1.apply(assertions.md:29)

Include an optional message to explain why the assertion failed.

assert(a > b, "a was smaller than b")
// munit.FailException: a was smaller than b
//  at munit.Assertions.fail(Assertions.scala:274)
//  at munit.Assertions.fail$(Assertions.scala:269)
//  at munit.FunSuite.fail(FunSuite.scala:13)
//  at munit.Assertions.$anonfun$assert$1(Assertions.scala:36)
//  at scala.runtime.java8.JFunction0$mcV$sp.apply(JFunction0$mcV$sp.scala:18)
//  at munit.internal.console.StackTraces$.dropInside(StackTraces.scala:10)
//  at munit.Assertions.assert(Assertions.scala:34)
//  at munit.Assertions.assert$(Assertions.scala:32)
//  at munit.FunSuite.assert(FunSuite.scala:13)
//  at repl.MdocSession$MdocApp$$anonfun$2.apply$mcV$sp(assertions.md:39)
//  at repl.MdocSession$MdocApp$$anonfun$2.apply(assertions.md:39)
//  at repl.MdocSession$MdocApp$$anonfun$2.apply(assertions.md:39)

Use clue() to include optional clues in the boolean condition based on values in the expression.

assert(clue(a) > clue(b))
// munit.FailException: assertion failed
// Clues {
//   a: Int = 1
//   b: Int = 2
// }
//  at munit.Assertions.fail(Assertions.scala:274)
//  at munit.Assertions.fail$(Assertions.scala:269)
//  at munit.FunSuite.fail(FunSuite.scala:13)
//  at munit.Assertions.$anonfun$assert$1(Assertions.scala:36)
//  at scala.runtime.java8.JFunction0$mcV$sp.apply(JFunction0$mcV$sp.scala:18)
//  at munit.internal.console.StackTraces$.dropInside(StackTraces.scala:10)
//  at munit.Assertions.assert(Assertions.scala:34)
//  at munit.Assertions.assert$(Assertions.scala:32)
//  at munit.FunSuite.assert(FunSuite.scala:13)
//  at repl.MdocSession$MdocApp$$anonfun$3.apply$mcV$sp(assertions.md:49)
//  at repl.MdocSession$MdocApp$$anonfun$3.apply(assertions.md:49)
//  at repl.MdocSession$MdocApp$$anonfun$3.apply(assertions.md:49)

Note, the -Yrangepos compiler option is required for clue() to work correctly. When -Yrangepos is not enabled you may see output like this instead:

// Clues {
//   : Int = 1
//   : Int = 2
// }

To fix this problem in sbt, add the following line to your settings:

 // build.sbt
 lazy val myProject = project
   .settings(
+    scalacOptions += "-Yrangepos"
   )

Clues can wrap more complicated expressions.

assert(clue(List(a).head) > clue(b))
// munit.FailException: assertion failed
// Clues {
//   List(a).head: Int = 1
//   b: Int = 2
// }
//  at munit.Assertions.fail(Assertions.scala:274)
//  at munit.Assertions.fail$(Assertions.scala:269)
//  at munit.FunSuite.fail(FunSuite.scala:13)
//  at munit.Assertions.$anonfun$assert$1(Assertions.scala:36)
//  at scala.runtime.java8.JFunction0$mcV$sp.apply(JFunction0$mcV$sp.scala:18)
//  at munit.internal.console.StackTraces$.dropInside(StackTraces.scala:10)
//  at munit.Assertions.assert(Assertions.scala:34)
//  at munit.Assertions.assert$(Assertions.scala:32)
//  at munit.FunSuite.assert(FunSuite.scala:13)
//  at repl.MdocSession$MdocApp$$anonfun$4.apply$mcV$sp(assertions.md:59)
//  at repl.MdocSession$MdocApp$$anonfun$4.apply(assertions.md:59)
//  at repl.MdocSession$MdocApp$$anonfun$4.apply(assertions.md:59)

assertEquals()

Use assertEquals() to assert that two values are the same.

assertEquals(a, b)
// munit.ComparisonFailException: values are not the same
// => Obtained
// 1
// => Diff (- expected, + obtained)
// -2
// +1
//  at munit.Assertions.failComparison(Assertions.scala:308)
//  at munit.Assertions.failComparison$(Assertions.scala:297)
//  at munit.FunSuite.failComparison(FunSuite.scala:13)
//  at munit.Compare.$anonfun$failEqualsComparison$1(Compare.scala:64)
//  at munit.Diffs$.assertNoDiff(Diffs.scala:36)
//  at munit.Compare.failEqualsComparison(Compare.scala:70)
//  at munit.Compare.failEqualsComparison$(Compare.scala:55)
//  at munit.Compare$$anonfun$1.failEqualsComparison(Compare.scala:104)
//  at munit.Assertions.$anonfun$assertEquals$1(Assertions.scala:134)
//  at scala.runtime.java8.JFunction0$mcV$sp.apply(JFunction0$mcV$sp.scala:18)
//  at munit.internal.console.StackTraces$.dropInside(StackTraces.scala:10)
//  at munit.Assertions.assertEquals(Assertions.scala:113)
//  at munit.Assertions.assertEquals$(Assertions.scala:104)
//  at munit.FunSuite.assertEquals(FunSuite.scala:13)
//  at repl.MdocSession$MdocApp$$anonfun$5.apply$mcV$sp(assertions.md:69)
//  at repl.MdocSession$MdocApp$$anonfun$5.apply(assertions.md:69)
//  at repl.MdocSession$MdocApp$$anonfun$5.apply(assertions.md:69)

The error message automatically produces a diff on assertion failure.

case class Library(name: String, awesome: Boolean, versions: Range = 0.to(1))
val munitLibrary = Library("MUnit", true)
// munitLibrary: Library = Library(
//   name = "MUnit",
//   awesome = true,
//   versions = Range(0, 1)
// )
val mdocLibrary = Library("MDoc", true)
// mdocLibrary: Library = Library(
//   name = "MDoc",
//   awesome = true,
//   versions = Range(0, 1)
// )
assertEquals(munitLibrary, mdocLibrary)
// munit.ComparisonFailException: values are not the same
// => Obtained
// Library(
//   name = "MUnit",
//   awesome = true,
//   versions = Range(
//     0,
//     1
//   )
// )
// => Diff (- expected, + obtained)
//  Library(
// -  name = "MDoc",
// +  name = "MUnit",
//    awesome = true,
//  at munit.Assertions.failComparison(Assertions.scala:308)
//  at munit.Assertions.failComparison$(Assertions.scala:297)
//  at munit.FunSuite.failComparison(FunSuite.scala:13)
//  at munit.Compare.$anonfun$failEqualsComparison$1(Compare.scala:64)
//  at munit.Diffs$.assertNoDiff(Diffs.scala:36)
//  at munit.Compare.failEqualsComparison(Compare.scala:70)
//  at munit.Compare.failEqualsComparison$(Compare.scala:55)
//  at munit.Compare$$anonfun$1.failEqualsComparison(Compare.scala:104)
//  at munit.Assertions.$anonfun$assertEquals$1(Assertions.scala:134)
//  at scala.runtime.java8.JFunction0$mcV$sp.apply(JFunction0$mcV$sp.scala:18)
//  at munit.internal.console.StackTraces$.dropInside(StackTraces.scala:10)
//  at munit.Assertions.assertEquals(Assertions.scala:113)
//  at munit.Assertions.assertEquals$(Assertions.scala:104)
//  at munit.FunSuite.assertEquals(FunSuite.scala:13)
//  at repl.MdocSession$MdocApp$$anonfun$6.apply$mcV$sp(assertions.md:91)
//  at repl.MdocSession$MdocApp$$anonfun$6.apply(assertions.md:91)
//  at repl.MdocSession$MdocApp$$anonfun$6.apply(assertions.md:91)

Diffs make it easy to track down differences even in large data structures.

assertEquals(
  Map(1 -> List(1.to(3))),
  Map(1 -> List(1.to(4)))
)
// munit.ComparisonFailException: values are not the same
// => Obtained
// Map(
//   1 -> List(
//     Range(
//       1,
//       2,
//       3
//     )
//   )
// )
// => Diff (- expected, + obtained)
//        2,
// -      3,
// -      4
// +      3
//      )
//  at munit.Assertions.failComparison(Assertions.scala:308)
//  at munit.Assertions.failComparison$(Assertions.scala:297)
//  at munit.FunSuite.failComparison(FunSuite.scala:13)
//  at munit.Compare.$anonfun$failEqualsComparison$1(Compare.scala:64)
//  at munit.Diffs$.assertNoDiff(Diffs.scala:36)
//  at munit.Compare.failEqualsComparison(Compare.scala:70)
//  at munit.Compare.failEqualsComparison$(Compare.scala:55)
//  at munit.Compare$$anonfun$1.failEqualsComparison(Compare.scala:104)
//  at munit.Assertions.$anonfun$assertEquals$1(Assertions.scala:134)
//  at scala.runtime.java8.JFunction0$mcV$sp.apply(JFunction0$mcV$sp.scala:18)
//  at munit.internal.console.StackTraces$.dropInside(StackTraces.scala:10)
//  at munit.Assertions.assertEquals(Assertions.scala:113)
//  at munit.Assertions.assertEquals$(Assertions.scala:104)
//  at munit.FunSuite.assertEquals(FunSuite.scala:13)
//  at repl.MdocSession$MdocApp$$anonfun$7.apply$mcV$sp(assertions.md:101)
//  at repl.MdocSession$MdocApp$$anonfun$7.apply(assertions.md:101)
//  at repl.MdocSession$MdocApp$$anonfun$7.apply(assertions.md:101)

Comparing two values of different types is a compile error.

assertEquals(Option("message"), "message")
// error: Can't compare these two types:
//   First type:  Option[String]
//   Second type: String
// Possible ways to fix this error:
//   Alternative 1: provide an implicit instance for Compare[Option[String], String]
//   Alternative 2: upcast either type into `Any` or a shared supertype
// Error occurred in an application involving default arguments.

It's a compile error even if the comparison is true at runtime.

assertEquals(List(1), Vector(1))
// error: Can't compare these two types:
//   First type:  List[Int]
//   Second type: scala.collection.immutable.Vector[Int]
// Possible ways to fix this error:
//   Alternative 1: provide an implicit instance for Compare[List[Int], scala.collection.immutable.Vector[Int]]
//   Alternative 2: upcast either type into `Any` or a shared supertype
// Error occurred in an application involving default arguments.
assertEquals('a', 'a'.toInt)
// error: Can't compare these two types:
//   First type:  Char
//   Second type: Int
// Possible ways to fix this error:
//   Alternative 1: provide an implicit instance for Compare[Char, Int]
//   Alternative 2: upcast either type into `Any` or a shared supertype
// Error occurred in an application involving default arguments.

It's OK to compare two types as long as one argument is a subtype of the other type.

assertEquals(Option(1), Some(1)) // OK
assertEquals(Some(1), Option(1)) // OK

Use assertEquals[Any, Any] if you think it's OK to compare the two types at runtime.

val right1: Either[String      , Int] = Right(42)
// right1: Either[String, Int] = Right(value = 42)
val right2: Either[List[String], Int] = Right(42)
// right2: Either[List[String], Int] = Right(value = 42)
assertEquals[Any, Any](right1, right2)

assertNotEquals()

Use assertNotEquals() to assert that two values are not the same.

assertNotEquals(a, a)
// munit.ComparisonFailException: values are the same, expected 2 different values: 1 is equal to 1
//  at munit.Assertions.failComparison(Assertions.scala:308)
//  at munit.Assertions.failComparison$(Assertions.scala:297)
//  at munit.FunSuite.failComparison(FunSuite.scala:13)
//  at munit.Assertions.$anonfun$assertNotEquals$1(Assertions.scala:78)
//  at scala.runtime.java8.JFunction0$mcV$sp.apply(JFunction0$mcV$sp.scala:18)
//  at munit.internal.console.StackTraces$.dropInside(StackTraces.scala:10)
//  at munit.Assertions.assertNotEquals(Assertions.scala:78)
//  at munit.Assertions.assertNotEquals$(Assertions.scala:73)
//  at munit.FunSuite.assertNotEquals(FunSuite.scala:13)
//  at repl.MdocSession$MdocApp$$anonfun$11.apply$mcV$sp(assertions.md:156)
//  at repl.MdocSession$MdocApp$$anonfun$11.apply(assertions.md:156)
//  at repl.MdocSession$MdocApp$$anonfun$11.apply(assertions.md:156)

The assertion does not fail when both values are different.

// OK
assertNotEquals(a, b)

assertNoDiff()

Use assertNoDiff() to compare two multiline strings.

val obtainedString = "val x = 41\nval y = 43\nval z = 43"
// obtainedString: String = """val x = 41
// val y = 43
// val z = 43"""
val expectedString = "val x = 41\nval y = 42\nval z = 43"
// expectedString: String = """val x = 41
// val y = 42
// val z = 43"""
assertNoDiff(obtainedString, expectedString)
// munit.ComparisonFailException: diff assertion failed
// => Obtained
// val x = 41
// val y = 43
// val z = 43
// => Diff (- expected, + obtained)
//  val x = 41
// -val y = 42
// +val y = 43
//  val z = 43
//  at munit.Assertions.failComparison(Assertions.scala:308)
//  at munit.Assertions.failComparison$(Assertions.scala:297)
//  at munit.FunSuite.failComparison(FunSuite.scala:13)
//  at munit.Assertions.$anonfun$exceptionHandlerFromAssertions$1(Assertions.scala:339)
//  at munit.Diffs$.assertNoDiff(Diffs.scala:36)
//  at munit.Assertions.$anonfun$assertNoDiff$1(Assertions.scala:61)
//  at scala.runtime.java8.JFunction0$mcZ$sp.apply(JFunction0$mcZ$sp.scala:17)
//  at munit.internal.console.StackTraces$.dropInside(StackTraces.scala:10)
//  at munit.Assertions.assertNoDiff(Assertions.scala:61)
//  at munit.Assertions.assertNoDiff$(Assertions.scala:56)
//  at munit.FunSuite.assertNoDiff(FunSuite.scala:13)
//  at repl.MdocSession$MdocApp$$anonfun$13.apply$mcV$sp(assertions.md:181)
//  at repl.MdocSession$MdocApp$$anonfun$13.apply(assertions.md:181)
//  at repl.MdocSession$MdocApp$$anonfun$13.apply(assertions.md:181)

The difference between assertNoDiff() and assertEquals() is that assertEquals() fails according to the == method while assertNoDiff() ignores non-visible differences such as trailing/leading whitespace, Windows/Unix newlines and ANSI color codes. The "=> Obtained" section of assertNoDiff() error messages also include copy-paste friendly syntax using .stripMargin.

intercept()

Use intercept() when you expect a particular exception to be thrown by the test code (i.e. the test succeeds if the given exception is thrown).

intercept[java.lang.IllegalArgumentException]{
   // code expected to throw exception here
}
// munit.FailException: expected exception of type 'java.lang.IllegalArgumentException' but body evaluated successfully
//  at munit.Assertions.fail(Assertions.scala:274)
//  at munit.Assertions.fail$(Assertions.scala:269)
//  at munit.FunSuite.fail(FunSuite.scala:13)
//  at munit.Assertions.runIntercept(Assertions.scala:201)
//  at munit.Assertions.intercept(Assertions.scala:183)
//  at munit.Assertions.intercept$(Assertions.scala:181)
//  at munit.FunSuite.intercept(FunSuite.scala:13)
//  at repl.MdocSession$MdocApp$$anonfun$14.apply(assertions.md:191)
//  at repl.MdocSession$MdocApp$$anonfun$14.apply(assertions.md:191)

interceptMessage()

Like intercept() except additionally asserts that the thrown exception has a specific error message.

interceptMessage[java.lang.IllegalArgumentException]("argument type mismatch"){
   // code expected to throw exception here
}
// munit.FailException: expected exception of type 'java.lang.IllegalArgumentException' but body evaluated successfully
//  at munit.Assertions.fail(Assertions.scala:274)
//  at munit.Assertions.fail$(Assertions.scala:269)
//  at munit.FunSuite.fail(FunSuite.scala:13)
//  at munit.Assertions.runIntercept(Assertions.scala:201)
//  at munit.Assertions.interceptMessage(Assertions.scala:191)
//  at munit.Assertions.interceptMessage$(Assertions.scala:188)
//  at munit.FunSuite.interceptMessage(FunSuite.scala:13)
//  at repl.MdocSession$MdocApp$$anonfun$15.apply(assertions.md:203)
//  at repl.MdocSession$MdocApp$$anonfun$15.apply(assertions.md:203)

fail()

Use fail() to make the test case fail immediately.

fail("test failed")
// munit.FailException: test failed
//  at munit.Assertions.fail(Assertions.scala:274)
//  at munit.Assertions.fail$(Assertions.scala:269)
//  at munit.FunSuite.fail(FunSuite.scala:13)
//  at repl.MdocSession$MdocApp$$anonfun$16.apply(assertions.md:215)
//  at repl.MdocSession$MdocApp$$anonfun$16.apply(assertions.md:215)

Use clues() to include optional context why the test failed.

fail("test failed", clues(a + b))
// munit.FailException: test failed
// Clues {
//   a + b: Int = 3
// }
//  at munit.Assertions.fail(Assertions.scala:274)
//  at munit.Assertions.fail$(Assertions.scala:269)
//  at munit.FunSuite.fail(FunSuite.scala:13)
//  at repl.MdocSession$MdocApp$$anonfun$17.apply(assertions.md:225)
//  at repl.MdocSession$MdocApp$$anonfun$17.apply(assertions.md:225)

compileErrors()

Use compileErrors() to assert that an example code snippet fails with a specific compile-time error message.

assertNoDiff(
  compileErrors("Set(2, 1).sorted"),
     """|error: value sorted is not a member of scala.collection.immutable.Set[Int]
        |Set(2, 1).sorted
        |          ^
        |""".stripMargin
)

The argument to compileErrors must be a string literal. It's not possible to pass in more complicated expressions such as variables or string interpolators.

val code = """val x: String = 2"""
compileErrors(code)
compileErrors(s"/* code */ $code")
// error: cannot compile dynamic expressions, only constant literals.
// To fix this problem, pass in a string literal in double quotes "..."
// compileErrors(code)
//               ^^^^
// error: cannot compile dynamic expressions, only constant literals.
// To fix this problem, pass in a string literal in double quotes "..."
// compileErrors(s"/* code */ $code")
//                             ^^^^

Inline the code variable to fix the compile error.

compileErrors("val x: String = 2")
// res9: String = """error:
// type mismatch;
//  found   : Int(2)
//  required: String
// val x: String = 2
//                 ^"""
← Declaring testsUsing fixtures →
  • assert()
  • assertEquals()
  • assertNotEquals()
  • assertNoDiff()
  • intercept()
  • interceptMessage()
  • fail()
  • compileErrors()
MUnit
Overview
Getting started
Social
Copyright © 2025 Scalameta