ScalaTest provides a powerful matcher system that enables readable test code and informative failure messages. The matcher system includes basic assertions, should/must matchers, and specialized matchers for different data types.
Core assertion methods available in all test suites.
trait Assertions {
/**
* Assert that a condition is true
*/
def assert(condition: Boolean): Assertion
def assert(condition: Boolean, clue: Any): Assertion
/**
* Assume a condition (will cancel the test if false rather than fail)
*/
def assume(condition: Boolean): Assertion
def assume(condition: Boolean, clue: Any): Assertion
/**
* Force test failure with optional message
*/
def fail(): Nothing
def fail(message: String): Nothing
def fail(message: String, cause: Throwable): Nothing
/**
* Mark test as pending
*/
def pending: Assertion with PendingStatement
def pending(message: String): Assertion with PendingStatement
/**
* Cancel test execution with optional message
*/
def cancel(): Nothing
def cancel(message: String): Nothing
def cancel(message: String, cause: Throwable): Nothing
/**
* Assert that a code block throws a specific exception
*/
def intercept[T <: AnyRef](f: => Any)(implicit classTag: ClassTag[T]): T
/**
* Assert that a code block throws an exception of any type
*/
def assertThrows[T <: AnyRef](f: => Any)(implicit classTag: ClassTag[T]): Assertion
/**
* Assert that a code block compiles successfully
*/
def assertCompiles(code: String): Assertion
/**
* Assert that a code block does not compile
*/
def assertDoesNotCompile(code: String): Assertion
/**
* Assert that a code block produces a type error
*/
def assertTypeError(code: String): Assertion
/**
* Add a clue to any assertion for better error messages
*/
def withClue[T](clue: Any)(fun: => T): T
}Usage Examples:
// Basic assertions
assert(2 + 2 == 4)
assert(2 + 2 == 4, "Basic math should work")
// Exception testing
val exception = intercept[IllegalArgumentException] {
throw new IllegalArgumentException("Invalid argument")
}
assert(exception.getMessage == "Invalid argument")
// Pending tests
pending // Mark test as pending
// Compile-time assertions (macros)
assertCompiles("val x: Int = 42")
assertDoesNotCompile("val x: String = 42")
assertTypeError("val x: String = 42")
// Enhanced error messages with clues
withClue("When testing user registration:") {
user.name should not be empty
user.email should include ("@")
}Expressive matchers using "should" syntax.
trait Matchers extends Assertions {
/**
* Equality matcher
*/
def equal(right: Any): Matcher[Any]
/**
* Identity matcher (checks object identity, not equality)
*/
def be(right: Any): Matcher[Any]
/**
* Greater than matcher
*/
def be(resultOfGreaterThanComparison: ResultOfGreaterThanComparison[_]): Matcher[Any]
/**
* Less than matcher
*/
def be(resultOfLessThanComparison: ResultOfLessThanComparison[_]): Matcher[Any]
/**
* Collection/string containment matcher
*/
def contain(element: Any): Matcher[Any]
/**
* String containment matchers
*/
def startWith(right: String): Matcher[String]
def endWith(right: String): Matcher[String]
def include(substring: String): Matcher[String]
/**
* Size/length matchers
*/
def have(resultOfLengthWordApplication: ResultOfLengthWordApplication): Matcher[Any]
def have(resultOfSizeWordApplication: ResultOfSizeWordApplication): Matcher[Any]
/**
* Type checking matchers
*/
def be(aType: ResultOfATypeInvocation[_]): Matcher[Any]
def be(anType: ResultOfAnTypeInvocation[_]): Matcher[Any]
/**
* Pattern matching matcher
*/
def matchPattern(right: PartialFunction[Any, _]): Matcher[Any]
}
/**
* Implicit conversion to enable should syntax on any value
*/
implicit class Shouldable[T](leftSideValue: T) {
def should(rightMatcherX1: Matcher[T]): Assertion
def should(beWord: BeWord): ResultOfBeWordForAny[T]
def should(notExist: NotExist.type): Assertion
def should(exist: Exist.type): Assertion
}Usage Examples:
import org.scalatest.matchers.should.Matchers
// Equality matchers
result should equal (42)
result should === (42) // Shorthand for equal
result should be (42)
// Comparison matchers
result should be > 10
result should be < 100
result should be >= 10
result should be <= 100
// String matchers
message should include ("error")
message should startWith ("Error:")
message should endWith ("failed")
message should fullyMatch regex "\\d+".r
// Collection matchers
list should contain (3)
list should contain oneOf (1, 2, 3)
list should contain allOf (1, 2, 3)
list should have length 3
list should have size 3
list should be (empty)
list should not be empty
// Type matchers
obj should be a [String]
obj should be an [IllegalArgumentException]
// Property matchers
obj should have (
Symbol("name") ("John"),
Symbol("age") (25)
)Alternative syntax using "must" instead of "should".
/**
* Implicit conversion to enable must syntax on any value
*/
implicit class Mustable[T](leftSideValue: T) {
def must(rightMatcherX1: Matcher[T]): Assertion
def must(beWord: BeWord): ResultOfBeWordForAny[T]
def must(notExist: NotExist.type): Assertion
def must(exist: Exist.type): Assertion
}Usage Examples:
import org.scalatest.matchers.must.Matchers
result must equal (42)
result must be > 10
message must include ("error")
list must contain (3)
list must have length 3Creating custom matchers for domain-specific testing.
trait Matcher[-T] extends (T => MatchResult) {
def apply(left: T): MatchResult
/**
* Compose this matcher with another using logical AND
*/
def and[U <: T](rightMatcher: Matcher[U]): Matcher[U]
/**
* Compose this matcher with another using logical OR
*/
def or[U <: T](rightMatcher: Matcher[U]): Matcher[U]
}
case class MatchResult(
matches: Boolean,
rawFailureMessage: String,
rawNegatedFailureMessage: String,
rawMidSentenceFailureMessage: String = "",
rawMidSentenceNegatedFailureMessage: String = ""
)Usage Examples:
// Custom matcher for even numbers
def beEven = Matcher { (left: Int) =>
MatchResult(
left % 2 == 0,
s"$left was not even",
s"$left was even"
)
}
// Usage
42 should beEven
43 should not be even
// Composing matchers
def bePositiveAndEven = be > 0 and beEven
// Custom matcher with parameters
def beWithinTolerance(expected: Double, tolerance: Double) =
Matcher { (actual: Double) =>
val difference = Math.abs(actual - expected)
MatchResult(
difference <= tolerance,
s"$actual was not within $tolerance of $expected",
s"$actual was within $tolerance of $expected"
)
}
// Usage
3.14159 should beWithinTolerance(3.14, 0.01)Matchers for collections that apply assertions to all or some elements.
trait Inspectors {
/**
* Assert that all elements satisfy the condition
*/
def forAll[E](xs: Iterable[E])(fun: E => Unit): Unit
/**
* Assert that at least one element satisfies the condition
*/
def forAtLeast(min: Int, xs: Iterable[_])(fun: Any => Unit): Unit
/**
* Assert that at most n elements satisfy the condition
*/
def forAtMost(max: Int, xs: Iterable[_])(fun: Any => Unit): Unit
/**
* Assert that exactly n elements satisfy the condition
*/
def forExactly(succeededCount: Int, xs: Iterable[_])(fun: Any => Unit): Unit
/**
* Assert that between min and max elements satisfy the condition
*/
def forBetween(from: Int, upTo: Int, xs: Iterable[_])(fun: Any => Unit): Unit
/**
* Assert that every element satisfies the condition (alias for forAll)
*/
def forEvery[E](xs: Iterable[E])(fun: E => Unit): Unit
}Usage Examples:
import org.scalatest.Inspectors
val numbers = List(1, 2, 3, 4, 5)
// All elements should be positive
forAll(numbers) { num =>
num should be > 0
}
// At least 3 elements should be even
forAtLeast(2, numbers) { num =>
num % 2 should equal (0)
}
// Exactly one element should equal 3
forExactly(1, numbers) { num =>
num should equal (3)
}/**
* Base matcher trait
*/
trait Matcher[-T] extends (T => MatchResult)
/**
* Helper words and phrases for building matcher expressions
*/
trait BeWord
trait HaveWord
trait ContainWord
trait ExistWord
trait NotExist
/**
* Result types for matcher expressions
*/
case class ResultOfBeWordForAny[T](left: T, shouldBeTrue: Boolean)
case class ResultOfLengthWordApplication(expectedLength: Long)
case class ResultOfSizeWordApplication(expectedSize: Long)
case class ResultOfGreaterThanComparison[T](right: T)
case class ResultOfLessThanComparison[T](right: T)
/**
* Type checking helpers
*/
case class ResultOfATypeInvocation[T](clazz: Class[T])
case class ResultOfAnTypeInvocation[T](clazz: Class[T])