scalaintermediate

Unit Testing with ScalaTest

Write unit tests with ScalaTest: FunSuite, FlatSpec, matchers, mocking, and async testing.

scala
import org.scalatest.funsuite.AnyFunSuite
import org.scalatest.flatspec.AnyFlatSpec
import org.scalatest.matchers.should.Matchers
import org.scalatest.BeforeAndAfterEach

// System under test
case class Calculator():
  def add(a: Int, b: Int): Int = a + b
  def divide(a: Double, b: Double): Either[String, Double] =
    if b == 0 then Left("Division by zero")
    else Right(a / b)
  def factorial(n: Int): BigInt =
    require(n >= 0, "Negative input")
    (1 to n).foldLeft(BigInt(1))(_ * _)

// FunSuite style
class CalculatorFunSuite extends AnyFunSuite:
  val calc = Calculator()

  test("add two positive numbers") {
    assert(calc.add(2, 3) == 5)
  }

  test("add negative numbers") {
    assert(calc.add(-1, -2) == -3)
  }

  test("divide by non-zero") {
    assert(calc.divide(10, 3) == Right(10.0 / 3))
  }

  test("divide by zero returns Left") {
    assert(calc.divide(10, 0) == Left("Division by zero"))
  }

// FlatSpec + Matchers style
class CalculatorSpec extends AnyFlatSpec with Matchers:
  val calc = Calculator()

  "Calculator.add" should "sum two integers" in {
    calc.add(2, 3) shouldBe 5
  }

  it should "handle zero" in {
    calc.add(0, 5) shouldBe 5
    calc.add(5, 0) shouldBe 5
  }

  "Calculator.divide" should "return Right for valid division" in {
    calc.divide(10, 2) shouldBe Right(5.0)
  }

  it should "return Left for division by zero" in {
    calc.divide(10, 0) shouldBe Left("Division by zero")
  }

  "Calculator.factorial" should "compute factorial" in {
    calc.factorial(0) shouldBe BigInt(1)
    calc.factorial(5) shouldBe BigInt(120)
    calc.factorial(10) shouldBe BigInt(3628800)
  }

  it should "throw on negative input" in {
    an [IllegalArgumentException] should be thrownBy {
      calc.factorial(-1)
    }
  }

// With setup/teardown
class StatefulSpec extends AnyFlatSpec with Matchers with BeforeAndAfterEach:
  var items: List[String] = _

  override def beforeEach(): Unit =
    items = List("a", "b", "c")

  "items" should "start with 3 elements" in {
    items should have length 3
  }

  it should "support filtering" in {
    items.filter(_ != "b") should contain theSameElementsAs List("a", "c")
  }

  // Collection matchers
  it should "demonstrate collection matchers" in {
    items should contain ("a")
    items should not contain ("z")
    items shouldBe sorted
    items should have size 3
  }

Use Cases

  • Unit testing Scala code
  • TDD with ScalaTest
  • Behavior-driven testing

Tags

Related Snippets

Similar patterns you can reuse in the same workflow.