Testing
Other styles: AnyFlatSpec ("X should Y in {...}"), AnyWordSpec, AnyFreeSpec, AsyncFunSuite for Futures.
24.1 MUnit
class MathSuite extends munit.FunSuite:
test("addition") {
assertEquals(1 + 1, 2)
}
test("exception") {
intercept[ArithmeticException](1 / 0)
}
test("option") {
assert(List(1, 2).headOption.contains(1), "should contain 1")
}
val tmpDir = FunFixture[os.Path](
setup = _ => os.temp.dir(),
teardown = dir => os.remove.all(dir))
tmpDir.test("uses fixture") { dir => assert(os.exists(dir)) }24.2 ScalaTest (many styles)
Other styles: AnyFlatSpec ("X should Y in {...}"), AnyWordSpec, AnyFreeSpec, AsyncFunSuite for Futures.
import org.scalatest.funsuite.AnyFunSuite
import org.scalatest.matchers.should.Matchers
class StackSpec extends AnyFunSuite with Matchers:
test("pop returns last pushed") {
val s = scala.collection.mutable.Stack(1, 2)
s.pop() shouldBe 2
s should have size 1
an[NoSuchElementException] should be thrownBy List.empty[Int].head
}24.3 Property-based testing with ScalaCheck
Custom generators: Gen.choose(1, 100), Gen.oneOf(...), Gen.listOf(...), Arbitrary. Integrations: munit-scalacheck, scalatestplus-scalacheck.
import org.scalacheck.Prop.forAll
import org.scalacheck.Properties
object ListProps extends Properties("List"):
property("reverse twice") = forAll((xs: List[Int]) => xs.reverse.reverse == xs)
property("concat length") = forAll((a: List[Int], b: List[Int]) => (a ++ b).length == a.length + b.length)24.4 Other testing tools
weaver-test (for Cats Effect), ZIO Test, utest (Li Haoyi).
Mocking: Mockito (via mockito-scala), scalamock — but prefer fakes/stubs via traits.
Integration tests: testcontainers-scala.
Coverage: scoverage (sbt coverage test coverageReport).
🧪 Part II Exercises
Model a library system: case class Book, enum Genre, a Library class with add/find/remove returning Either.
Implement a sealed trait Expr (Num, Add, Mul, Neg, Var) with eval(env: Map[String, Int]) and simplify.
Write a custom extractor object IPv4 that destructures "192.168.0.1" into four ints.
Implement a binary search tree as a generic enum Tree[A] with insert, contains, and in-order traversal.
Count word frequencies in a file with Source and groupMapReduce; print top 10.
Use stackable traits to build a logger with Timestamped, Uppercase, and Filtered behaviors.
Write a for-comprehension validating a registration form (name, email, age) with Either.
Implement LazyList of primes (sieve) and print the first 20.
Add extension methods to Int: isPrime, factorial, digits.
Write MUnit tests and ScalaCheck properties for exercises 2 and 4.