ScalaTest is a comprehensive testing framework for Scala and Java that provides multiple testing styles and sophisticated matcher libraries.
—
ScalaTest provides comprehensive assertion capabilities with macro-enhanced error messages and a rich natural language matcher DSL. The framework includes both basic assertions and sophisticated matcher expressions for clear, readable test code.
Basic assertion methods available in all ScalaTest suites through the Assertions trait.
import org.scalatest.Assertions
trait Assertions {
// Basic assertions
def assert(condition: Boolean)(implicit prettifier: Prettifier, pos: source.Position): Assertion
def assert(condition: Boolean, clue: Any)(implicit prettifier: Prettifier, pos: source.Position): Assertion
// Expected result assertions
def assertResult(expected: Any)(actual: Any)(implicit prettifier: Prettifier, pos: source.Position): Assertion
def assertResult(expected: Any, clue: Any)(actual: Any)(implicit prettifier: Prettifier, pos: source.Position): Assertion
// Exception assertions
def assertThrows[T <: AnyRef](code: => Any)(implicit classTag: ClassTag[T], pos: source.Position): Assertion
def intercept[T <: AnyRef](code: => Any)(implicit classTag[T], pos: source.Position): T
// Assumptions (skips test if false)
def assume(condition: Boolean)(implicit prettifier: Prettifier, pos: source.Position): Assertion
def assume(condition: Boolean, clue: Any)(implicit prettifier: Prettifier, pos: source.Position): Assertion
// Test control
def fail()(implicit pos: source.Position): Nothing
def fail(message: String)(implicit pos: source.Position): Nothing
def cancel()(implicit pos: source.Position): Nothing
def cancel(message: String)(implicit pos: source.Position): Nothing
def pending: Assertion with PendingStatement
// Contextual information
def withClue[T](clue: Any)(fun: => T): T
// Success value
val succeed: Assertion
}Basic Assertion Examples:
import org.scalatest.funsuite.AnyFunSuite
class AssertionExamples extends AnyFunSuite {
test("basic assertions") {
assert(2 + 2 == 4)
assert(2 + 2 == 4, "addition should work")
assertResult(4) {
2 + 2
}
assertThrows[ArithmeticException] {
1 / 0
}
val exception = intercept[IllegalArgumentException] {
throw new IllegalArgumentException("test")
}
assert(exception.getMessage == "test")
}
test("assumptions and test control") {
assume(System.getProperty("env") == "test", "Only run in test environment")
// This will mark test as pending
pending
// Add contextual information to failures
withClue("When testing division") {
assert(10 / 2 == 5)
}
}
}Enhanced equality assertion with better error messages.
trait TripleEquals {
def ===(right: Any): TripleEqualsInvocation[Any]
def !==(right: Any): TripleEqualsInvocation[Any]
}
// Usage in assertions
assert(left === right)
assert(left !== right)Triple Equals Examples:
test("triple equals") {
val list = List(1, 2, 3)
assert(list === List(1, 2, 3)) // Better error messages than ==
assert(list !== List(1, 2, 4))
val map = Map("a" -> 1, "b" -> 2)
assert(map === Map("a" -> 1, "b" -> 2))
}Natural language matcher expressions for readable test assertions.
import org.scalatest.matchers.should.Matchers
trait Matchers {
// Implicit conversion to enable "should" syntax
implicit def convertToAnyShouldWrapper[T](o: T): AnyShouldWrapper[T]
// Core matcher words
val be: BeWord
val not: NotWord
val have: HaveWord
val contain: ContainWord
val startWith: StartWithWord
val endWith: EndWithWord
val include: IncludeWord
val matchPattern: MatchPatternWord
}
// Basic equality and identity
value should equal(expected)
value should be(expected)
value should not equal(unexpected)
value should not be(unexpected)
// Comparison matchers
value should be > 5
value should be >= 5
value should be < 10
value should be <= 10
// Type matchers
value should be a [String]
value should be an [Integer]
// Boolean matchers
condition should be(true)
condition should be(false)Should Matcher Examples:
import org.scalatest.flatspec.AnyFlatSpec
import org.scalatest.matchers.should.Matchers
class MatcherExamples extends AnyFlatSpec with Matchers {
"Basic matchers" should "work with equality" in {
val result = 2 + 2
result should equal(4)
result should be(4)
result should not equal(5)
}
"Comparison matchers" should "work with numbers" in {
val score = 85
score should be > 80
score should be >= 85
score should be < 90
score should be <= 85
}
"Type matchers" should "check types" in {
val value: Any = "hello"
value should be a [String]
val number: Any = 42
number should be an [Integer]
}
}Specialized matchers for string operations.
// String content matchers
string should startWith("prefix")
string should endWith("suffix")
string should include("substring")
string should not include("unwanted")
// Regular expression matchers
string should fullyMatch regex "\\d+".r
string should startWith regex "\\w+".r
string should endWith regex "\\d+".r
string should include regex "\\w+@\\w+".r
// Length matchers
string should have length 10
string should not have length(5)String Matcher Examples:
test("string matchers") {
val email = "user@example.com"
email should startWith("user")
email should endWith(".com")
email should include("@")
email should not include("password")
email should fullyMatch regex "\\w+@\\w+\\.\\w+".r
email should have length 16
}Matchers for various collection operations and properties.
// Element presence
collection should contain(element)
collection should contain oneOf(elem1, elem2, elem3)
collection should contain noneOf(elem1, elem2, elem3)
collection should contain allOf(elem1, elem2, elem3)
collection should contain only(elem1, elem2, elem3)
collection should contain theSameElementsAs(otherCollection)
// Collection properties
collection should be(empty)
collection should not be empty
collection should have length 5
collection should have size 5
// Sequence-specific matchers
sequence should contain inOrder(elem1, elem2, elem3)
sequence should contain inOrderOnly(elem1, elem2, elem3)
sequence should contain theSameElementsInOrderAs(otherSequence)
// Key-value matchers (for Maps)
map should contain key("key")
map should contain value("value")
map should contain entry("key" -> "value")Collection Matcher Examples:
test("collection matchers") {
val numbers = List(1, 2, 3, 4, 5)
numbers should contain(3)
numbers should contain oneOf(2, 7, 9)
numbers should contain noneOf(6, 7, 8)
numbers should contain allOf(1, 2, 3)
numbers should have length 5
numbers should not be empty
val fruits = List("apple", "banana", "cherry")
fruits should contain inOrder("apple", "banana")
fruits should contain only("cherry", "apple", "banana")
val scores = Map("alice" -> 85, "bob" -> 92)
scores should contain key("alice")
scores should contain value(92)
scores should contain entry("alice" -> 85)
}Matchers for testing exception behavior.
// Exception type matchers
a [ExceptionType] should be thrownBy { code }
an [ExceptionType] should be thrownBy { code }
noException should be thrownBy { code }
// Exception message matchers
the [ExceptionType] thrownBy { code } should have message "expected message"
the [ExceptionType] thrownBy { code } should have message that startsWith("prefix")
the [ExceptionType] thrownBy { code } should have message that endsWith("suffix")
the [ExceptionType] thrownBy { code } should have message that include("substring")Exception Matcher Examples:
test("exception matchers") {
a [ArithmeticException] should be thrownBy {
10 / 0
}
an [IllegalArgumentException] should be thrownBy {
require(false, "Invalid argument")
}
the [IllegalArgumentException] thrownBy {
require(false, "Invalid argument")
} should have message "requirement failed: Invalid argument"
noException should be thrownBy {
val result = 10 / 2
assert(result == 5)
}
}Matchers for object properties and custom validations.
// Built-in property matchers
object should have(
'property(expectedValue),
'anotherProperty(anotherValue)
)
// Length and size properties
collection should have length 10
collection should have size 10
// Custom property matchers
def startWith(expectedPrefix: String) = new HavePropertyMatcher[String, String] {
def apply(left: String) = HavePropertyMatchResult(
left.startsWith(expectedPrefix),
"prefix",
expectedPrefix,
left
)
}
string should have(startWith("Hello"))Property Matcher Examples:
test("property matchers") {
case class Person(name: String, age: Int)
val person = Person("Alice", 30)
// Using symbol-based property matching
person should have(
'name("Alice"),
'age(30)
)
val list = List(1, 2, 3)
list should have length 3
list should have size 3
}Creating custom matchers for domain-specific assertions.
import org.scalatest.matchers.{BeMatcher, MatchResult, Matcher}
// Custom BeMatcher
def beEven = BeMatcher { (left: Int) =>
MatchResult(
left % 2 == 0,
s"$left was not even",
s"$left was even"
)
}
// Custom Matcher
def startWith(expectedStart: String) = Matcher { (left: String) =>
MatchResult(
left.startsWith(expectedStart),
s"""String "$left" did not start with "$expectedStart"""",
s"""String "$left" started with "$expectedStart""""
)
}
// Usage
number should beEven
string should startWith("Hello")Custom Matcher Examples:
import org.scalatest.matchers.{BeMatcher, MatchResult}
class CustomMatcherExamples extends AnyFlatSpec with Matchers {
def beEven = BeMatcher { (left: Int) =>
MatchResult(
left % 2 == 0,
s"$left was not even",
s"$left was even"
)
}
def haveDigits(expectedCount: Int) = Matcher { (left: String) =>
val digitCount = left.count(_.isDigit)
MatchResult(
digitCount == expectedCount,
s"""String "$left" had $digitCount digits, not $expectedCount""",
s"""String "$left" had $expectedCount digits"""
)
}
"Custom matchers" should "work correctly" in {
4 should beEven
3 should not be even
"abc123def" should haveDigits(3)
"hello" should haveDigits(0)
}
}Alternative matcher syntax using "must" instead of "should".
import org.scalatest.matchers.must.Matchers
// Same API as should matchers but with "must"
value must equal(expected)
value must be > 5
collection must contain("element")
a [Exception] must be thrownBy { code }import org.scalatest.TolerantNumerics
// Floating point comparisons with tolerance
val tolerantDoubleEquality = TolerantNumerics.tolerantDoubleEquality(0.01)
implicit val doubleEq = tolerantDoubleEquality
3.14159 should equal(3.14 +- 0.01)
3.14159 should be(3.14 +- 0.01)import org.scalactic.Equality
// Custom equality for case-insensitive string comparison
implicit val stringEq = new Equality[String] {
def areEqual(left: String, right: Any): Boolean =
right match {
case str: String => left.toLowerCase == str.toLowerCase
case _ => false
}
}
"Hello" should equal("HELLO") // Uses custom equalityApply matchers to all elements of collections.
import org.scalatest.Inspectors
// Apply matcher to all elements
all(collection) should be > 0
all(collection) should startWith("prefix")
// Apply matcher to at least one element
atLeast(1, collection) should be > 10
atMost(3, collection) should be < 5
exactly(2, collection) should equal("expected")
// Apply matcher to between n and m elements
between(2, 4, collection) should include("substring")Inspector Examples:
import org.scalatest.Inspectors
test("inspector methods") {
val numbers = List(1, 2, 3, 4, 5)
all(numbers) should be > 0
all(numbers) should be <= 5
atLeast(1, numbers) should be > 3
atMost(2, numbers) should be > 4
exactly(1, numbers) should equal(3)
val words = List("hello", "world", "test")
all(words) should have length be > 3
}Install with Tessl CLI
npx tessl i tessl/maven-org-scalatest--scalatest-2-11