scalaintermediate
Testing with Specs2 Framework
Write readable tests with specs2: acceptance specs, matchers, data tables, and mock integration.
scalaPress ⌘/Ctrl + Shift + C to copy
import org.specs2.mutable.Specification
import org.specs2.specification.core.SpecStructure
// Unit under test
class Calculator:
def add(a: Int, b: Int): Int = a + b
def divide(a: Int, b: Int): Either[String, Double] =
if b == 0 then Left("Division by zero")
else Right(a.toDouble / b)
def fibonacci(n: Int): Int =
if n <= 1 then n
else fibonacci(n - 1) + fibonacci(n - 2)
class StringUtils:
def capitalize(s: String): String =
if s.isEmpty then s
else s.head.toUpper + s.tail.toLowerCase
def isPalindrome(s: String): Boolean =
val clean = s.toLowerCase.filter(_.isLetterOrDigit)
clean == clean.reverse
def wordCount(s: String): Map[String, Int] =
s.toLowerCase.split("\\s+")
.filter(_.nonEmpty)
.groupBy(identity)
.view.mapValues(_.length).toMap
// Mutable specification (xUnit-style)
class CalculatorSpec extends Specification:
"Calculator" >> {
val calc = Calculator()
"add" >> {
"add two positive numbers" >> {
calc.add(2, 3) must_== 5
}
"add negative numbers" >> {
calc.add(-1, -2) must_== -3
}
"add zero" >> {
calc.add(0, 5) must_== 5
}
}
"divide" >> {
"divide normally" >> {
calc.divide(10, 3) must beRight(beCloseTo(3.33 +/- 0.01))
}
"return error for zero divisor" >> {
calc.divide(10, 0) must beLeft("Division by zero")
}
}
"fibonacci" >> {
"return 0 for 0" >> { calc.fibonacci(0) must_== 0 }
"return 1 for 1" >> { calc.fibonacci(1) must_== 1 }
"return 8 for 6" >> { calc.fibonacci(6) must_== 8 }
}
}
// String utils spec with matchers
class StringUtilsSpec extends Specification:
"StringUtils" >> {
val utils = StringUtils()
"capitalize" >> {
"capitalize first letter" >> {
utils.capitalize("hello") must_== "Hello"
}
"handle empty string" >> {
utils.capitalize("") must beEmpty
}
"handle single char" >> {
utils.capitalize("a") must_== "A"
}
"lowercase rest" >> {
utils.capitalize("hELLO") must_== "Hello"
}
}
"isPalindrome" >> {
"detect palindrome" >> {
utils.isPalindrome("racecar") must beTrue
}
"ignore case" >> {
utils.isPalindrome("RaceCar") must beTrue
}
"ignore non-alphanumeric" >> {
utils.isPalindrome("A man, a plan, a canal: Panama") must beTrue
}
"reject non-palindrome" >> {
utils.isPalindrome("hello") must beFalse
}
}
"wordCount" >> {
"count words" >> {
utils.wordCount("hello world hello") must_== Map(
"hello" -> 2,
"world" -> 1
)
}
"handle empty" >> {
utils.wordCount("") must beEmpty
}
}
}
// Matchers showcase
class MatchersSpec extends Specification:
"Matchers" >> {
// Equality
"equality" >> { 1 + 1 must_== 2 }
// Comparison
"comparison" >> {
5 must beGreaterThan(3)
2 must beLessThanOrEqualTo(2)
3.14 must beCloseTo(3.14 +/- 0.001)
}
// String matchers
"strings" >> {
"hello world" must contain("world")
"hello" must startWith("hel")
"hello" must endWith("llo")
"hello" must have length 5
"hello" must beMatching("h.*o")
}
// Collection matchers
"collections" >> {
List(1, 2, 3) must contain(2)
List(1, 2, 3) must have size 3
List(1, 2, 3) must containAllOf(List(1, 3))
List(3, 1, 2) must beSorted.not
List.empty[Int] must beEmpty
}
// Option/Either
"option" >> {
Some(42) must beSome(42)
None must beNone
}
// Exception
"exception" >> {
{ throw RuntimeException("boom") } must throwA[RuntimeException](message = "boom")
}
}Use Cases
- Behavior-driven development
- Readable test specifications
- Comprehensive assertion matching
Tags
Related Snippets
Similar patterns you can reuse in the same workflow.
scalaintermediate
Unit Testing with ScalaTest
Write unit tests with ScalaTest: FunSuite, FlatSpec, matchers, mocking, and async testing.
Best for: Unit testing Scala code
#scala#testing
scalaintermediate
Property-Based Testing with ScalaCheck
Write property-based tests with ScalaCheck: generators, properties, shrinking, and custom Arbitrary.
Best for: Exhaustive testing with random inputs
#scala#testing
scalaintermediate
Testing with Mocks and Stubs
Write testable Scala code with trait-based mocks, stubs, and dependency substitution.
Best for: Unit testing with dependency injection
#scala#testing
javaintermediate
JUnit 5 — Test Patterns and Assertions
Write JUnit 5 tests with assertions, lifecycle hooks, nested tests, parameterized tests, and dynamic tests.
Best for: Unit testing Java applications with JUnit 5
#java#junit