Scala Testing
A professional Scala project ships with tests. The two most common test libraries are ScalaTest, a mature, feature-rich framework with several testing styles, and MUnit, a smaller, faster library with a JUnit-like feel. Both integrate directly with
sbt test.
Project Setup
Test libraries live in build.sbt under the Test configuration, so they are only on the classpath when running tests, never in the packaged artifact.
Example (build.sbt):
libraryDependencies += "org.scalatest" %% "scalatest" % "3.2.19" % Test
// or, for MUnit:
// libraryDependencies += "org.scalameta" %% "munit" % "1.0.0" % Test
ScalaTest Basics
The most common ScalaTest style is AnyFunSuite: each test is a call to test("description") { ... } containing one or more assertions.
Example:
import org.scalatest.funsuite.AnyFunSuite
class MathUtilsSuite extends AnyFunSuite {
def add(a: Int, b: Int): Int = a + b
test("add sums two positive numbers") {
assert(add(2, 3) == 5)
}
test("add handles negative numbers") {
assertResult(-1) {
add(2, -3)
}
}
test("division by zero throws") {
assertThrows[ArithmeticException] {
10 / 0
}
}
}
MUnit Basics
MUnit favors plain assertEquals calls and reads closer to JUnit. It starts faster and has fewer moving parts, which makes it a common default for new projects.
Example:
class MathUtilsSuite extends munit.FunSuite {
def add(a: Int, b: Int): Int = a + b
test("add sums two positive numbers") {
assertEquals(add(2, 3), 5)
}
test("division by zero throws") {
intercept[ArithmeticException] {
10 / 0
}
}
}
Fixtures
A fixture sets up shared state before each test and tears it down after. In ScalaTest, override withFixture or mix in a fixture trait; in MUnit, override beforeEach/afterEach.
Example (MUnit):
class RepositorySuite extends munit.FunSuite {
var data: List[Int] = _
override def beforeEach(context: BeforeEach): Unit = {
data = List(1, 2, 3)
}
test("data starts with three elements") {
assertEquals(data.length, 3)
}
}
Running Tests
Run the whole suite, a single test class, or watch and re-run on every file save.
sbt test # run every test
sbt "testOnly *MathUtilsSuite" # run one suite
sbt ~test # re-run on file change
Practice move: add a ScalaTest or MUnit dependency to a small project, write one failing test on purpose, watch it fail with a clear message, then make it pass.