0
# Assertions and Matchers
1
2
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.
3
4
## Capabilities
5
6
### Core Assertions
7
8
Basic assertion methods available in all ScalaTest suites through the `Assertions` trait.
9
10
```scala { .api }
11
import org.scalatest.Assertions
12
13
trait Assertions {
14
// Basic assertions
15
def assert(condition: Boolean)(implicit prettifier: Prettifier, pos: source.Position): Assertion
16
def assert(condition: Boolean, clue: Any)(implicit prettifier: Prettifier, pos: source.Position): Assertion
17
18
// Expected result assertions
19
def assertResult(expected: Any)(actual: Any)(implicit prettifier: Prettifier, pos: source.Position): Assertion
20
def assertResult(expected: Any, clue: Any)(actual: Any)(implicit prettifier: Prettifier, pos: source.Position): Assertion
21
22
// Exception assertions
23
def assertThrows[T <: AnyRef](code: => Any)(implicit classTag: ClassTag[T], pos: source.Position): Assertion
24
def intercept[T <: AnyRef](code: => Any)(implicit classTag[T], pos: source.Position): T
25
26
// Assumptions (skips test if false)
27
def assume(condition: Boolean)(implicit prettifier: Prettifier, pos: source.Position): Assertion
28
def assume(condition: Boolean, clue: Any)(implicit prettifier: Prettifier, pos: source.Position): Assertion
29
30
// Test control
31
def fail()(implicit pos: source.Position): Nothing
32
def fail(message: String)(implicit pos: source.Position): Nothing
33
def cancel()(implicit pos: source.Position): Nothing
34
def cancel(message: String)(implicit pos: source.Position): Nothing
35
def pending: Assertion with PendingStatement
36
37
// Contextual information
38
def withClue[T](clue: Any)(fun: => T): T
39
40
// Success value
41
val succeed: Assertion
42
}
43
```
44
45
**Basic Assertion Examples:**
46
```scala
47
import org.scalatest.funsuite.AnyFunSuite
48
49
class AssertionExamples extends AnyFunSuite {
50
test("basic assertions") {
51
assert(2 + 2 == 4)
52
assert(2 + 2 == 4, "addition should work")
53
54
assertResult(4) {
55
2 + 2
56
}
57
58
assertThrows[ArithmeticException] {
59
1 / 0
60
}
61
62
val exception = intercept[IllegalArgumentException] {
63
throw new IllegalArgumentException("test")
64
}
65
assert(exception.getMessage == "test")
66
}
67
68
test("assumptions and test control") {
69
assume(System.getProperty("env") == "test", "Only run in test environment")
70
71
// This will mark test as pending
72
pending
73
74
// Add contextual information to failures
75
withClue("When testing division") {
76
assert(10 / 2 == 5)
77
}
78
}
79
}
80
```
81
82
### Triple Equals (===)
83
84
Enhanced equality assertion with better error messages.
85
86
```scala { .api }
87
trait TripleEquals {
88
def ===(right: Any): TripleEqualsInvocation[Any]
89
def !==(right: Any): TripleEqualsInvocation[Any]
90
}
91
92
// Usage in assertions
93
assert(left === right)
94
assert(left !== right)
95
```
96
97
**Triple Equals Examples:**
98
```scala
99
test("triple equals") {
100
val list = List(1, 2, 3)
101
assert(list === List(1, 2, 3)) // Better error messages than ==
102
assert(list !== List(1, 2, 4))
103
104
val map = Map("a" -> 1, "b" -> 2)
105
assert(map === Map("a" -> 1, "b" -> 2))
106
}
107
```
108
109
### Should Matchers DSL
110
111
Natural language matcher expressions for readable test assertions.
112
113
```scala { .api }
114
import org.scalatest.matchers.should.Matchers
115
116
trait Matchers {
117
// Implicit conversion to enable "should" syntax
118
implicit def convertToAnyShouldWrapper[T](o: T): AnyShouldWrapper[T]
119
120
// Core matcher words
121
val be: BeWord
122
val not: NotWord
123
val have: HaveWord
124
val contain: ContainWord
125
val startWith: StartWithWord
126
val endWith: EndWithWord
127
val include: IncludeWord
128
val matchPattern: MatchPatternWord
129
}
130
131
// Basic equality and identity
132
value should equal(expected)
133
value should be(expected)
134
value should not equal(unexpected)
135
value should not be(unexpected)
136
137
// Comparison matchers
138
value should be > 5
139
value should be >= 5
140
value should be < 10
141
value should be <= 10
142
143
// Type matchers
144
value should be a [String]
145
value should be an [Integer]
146
147
// Boolean matchers
148
condition should be(true)
149
condition should be(false)
150
```
151
152
**Should Matcher Examples:**
153
```scala
154
import org.scalatest.flatspec.AnyFlatSpec
155
import org.scalatest.matchers.should.Matchers
156
157
class MatcherExamples extends AnyFlatSpec with Matchers {
158
"Basic matchers" should "work with equality" in {
159
val result = 2 + 2
160
result should equal(4)
161
result should be(4)
162
result should not equal(5)
163
}
164
165
"Comparison matchers" should "work with numbers" in {
166
val score = 85
167
score should be > 80
168
score should be >= 85
169
score should be < 90
170
score should be <= 85
171
}
172
173
"Type matchers" should "check types" in {
174
val value: Any = "hello"
175
value should be a [String]
176
177
val number: Any = 42
178
number should be an [Integer]
179
}
180
}
181
```
182
183
### String Matchers
184
185
Specialized matchers for string operations.
186
187
```scala { .api }
188
// String content matchers
189
string should startWith("prefix")
190
string should endWith("suffix")
191
string should include("substring")
192
string should not include("unwanted")
193
194
// Regular expression matchers
195
string should fullyMatch regex "\\d+".r
196
string should startWith regex "\\w+".r
197
string should endWith regex "\\d+".r
198
string should include regex "\\w+@\\w+".r
199
200
// Length matchers
201
string should have length 10
202
string should not have length(5)
203
```
204
205
**String Matcher Examples:**
206
```scala
207
test("string matchers") {
208
val email = "user@example.com"
209
210
email should startWith("user")
211
email should endWith(".com")
212
email should include("@")
213
email should not include("password")
214
215
email should fullyMatch regex "\\w+@\\w+\\.\\w+".r
216
email should have length 16
217
}
218
```
219
220
### Collection Matchers
221
222
Matchers for various collection operations and properties.
223
224
```scala { .api }
225
// Element presence
226
collection should contain(element)
227
collection should contain oneOf(elem1, elem2, elem3)
228
collection should contain noneOf(elem1, elem2, elem3)
229
collection should contain allOf(elem1, elem2, elem3)
230
collection should contain only(elem1, elem2, elem3)
231
collection should contain theSameElementsAs(otherCollection)
232
233
// Collection properties
234
collection should be(empty)
235
collection should not be empty
236
collection should have length 5
237
collection should have size 5
238
239
// Sequence-specific matchers
240
sequence should contain inOrder(elem1, elem2, elem3)
241
sequence should contain inOrderOnly(elem1, elem2, elem3)
242
sequence should contain theSameElementsInOrderAs(otherSequence)
243
244
// Key-value matchers (for Maps)
245
map should contain key("key")
246
map should contain value("value")
247
map should contain entry("key" -> "value")
248
```
249
250
**Collection Matcher Examples:**
251
```scala
252
test("collection matchers") {
253
val numbers = List(1, 2, 3, 4, 5)
254
255
numbers should contain(3)
256
numbers should contain oneOf(2, 7, 9)
257
numbers should contain noneOf(6, 7, 8)
258
numbers should contain allOf(1, 2, 3)
259
numbers should have length 5
260
numbers should not be empty
261
262
val fruits = List("apple", "banana", "cherry")
263
fruits should contain inOrder("apple", "banana")
264
fruits should contain only("cherry", "apple", "banana")
265
266
val scores = Map("alice" -> 85, "bob" -> 92)
267
scores should contain key("alice")
268
scores should contain value(92)
269
scores should contain entry("alice" -> 85)
270
}
271
```
272
273
### Exception Matchers
274
275
Matchers for testing exception behavior.
276
277
```scala { .api }
278
// Exception type matchers
279
a [ExceptionType] should be thrownBy { code }
280
an [ExceptionType] should be thrownBy { code }
281
noException should be thrownBy { code }
282
283
// Exception message matchers
284
the [ExceptionType] thrownBy { code } should have message "expected message"
285
the [ExceptionType] thrownBy { code } should have message that startsWith("prefix")
286
the [ExceptionType] thrownBy { code } should have message that endsWith("suffix")
287
the [ExceptionType] thrownBy { code } should have message that include("substring")
288
```
289
290
**Exception Matcher Examples:**
291
```scala
292
test("exception matchers") {
293
a [ArithmeticException] should be thrownBy {
294
10 / 0
295
}
296
297
an [IllegalArgumentException] should be thrownBy {
298
require(false, "Invalid argument")
299
}
300
301
the [IllegalArgumentException] thrownBy {
302
require(false, "Invalid argument")
303
} should have message "requirement failed: Invalid argument"
304
305
noException should be thrownBy {
306
val result = 10 / 2
307
assert(result == 5)
308
}
309
}
310
```
311
312
### Property Matchers
313
314
Matchers for object properties and custom validations.
315
316
```scala { .api }
317
// Built-in property matchers
318
object should have(
319
'property(expectedValue),
320
'anotherProperty(anotherValue)
321
)
322
323
// Length and size properties
324
collection should have length 10
325
collection should have size 10
326
327
// Custom property matchers
328
def startWith(expectedPrefix: String) = new HavePropertyMatcher[String, String] {
329
def apply(left: String) = HavePropertyMatchResult(
330
left.startsWith(expectedPrefix),
331
"prefix",
332
expectedPrefix,
333
left
334
)
335
}
336
337
string should have(startWith("Hello"))
338
```
339
340
**Property Matcher Examples:**
341
```scala
342
test("property matchers") {
343
case class Person(name: String, age: Int)
344
val person = Person("Alice", 30)
345
346
// Using symbol-based property matching
347
person should have(
348
'name("Alice"),
349
'age(30)
350
)
351
352
val list = List(1, 2, 3)
353
list should have length 3
354
list should have size 3
355
}
356
```
357
358
### Custom Matchers
359
360
Creating custom matchers for domain-specific assertions.
361
362
```scala { .api }
363
import org.scalatest.matchers.{BeMatcher, MatchResult, Matcher}
364
365
// Custom BeMatcher
366
def beEven = BeMatcher { (left: Int) =>
367
MatchResult(
368
left % 2 == 0,
369
s"$left was not even",
370
s"$left was even"
371
)
372
}
373
374
// Custom Matcher
375
def startWith(expectedStart: String) = Matcher { (left: String) =>
376
MatchResult(
377
left.startsWith(expectedStart),
378
s"""String "$left" did not start with "$expectedStart"""",
379
s"""String "$left" started with "$expectedStart""""
380
)
381
}
382
383
// Usage
384
number should beEven
385
string should startWith("Hello")
386
```
387
388
**Custom Matcher Examples:**
389
```scala
390
import org.scalatest.matchers.{BeMatcher, MatchResult}
391
392
class CustomMatcherExamples extends AnyFlatSpec with Matchers {
393
def beEven = BeMatcher { (left: Int) =>
394
MatchResult(
395
left % 2 == 0,
396
s"$left was not even",
397
s"$left was even"
398
)
399
}
400
401
def haveDigits(expectedCount: Int) = Matcher { (left: String) =>
402
val digitCount = left.count(_.isDigit)
403
MatchResult(
404
digitCount == expectedCount,
405
s"""String "$left" had $digitCount digits, not $expectedCount""",
406
s"""String "$left" had $expectedCount digits"""
407
)
408
}
409
410
"Custom matchers" should "work correctly" in {
411
4 should beEven
412
3 should not be even
413
414
"abc123def" should haveDigits(3)
415
"hello" should haveDigits(0)
416
}
417
}
418
```
419
420
### Must Matchers
421
422
Alternative matcher syntax using "must" instead of "should".
423
424
```scala { .api }
425
import org.scalatest.matchers.must.Matchers
426
427
// Same API as should matchers but with "must"
428
value must equal(expected)
429
value must be > 5
430
collection must contain("element")
431
a [Exception] must be thrownBy { code }
432
```
433
434
## Tolerance and Equality
435
436
### Numeric Tolerance
437
438
```scala { .api }
439
import org.scalatest.TolerantNumerics
440
441
// Floating point comparisons with tolerance
442
val tolerantDoubleEquality = TolerantNumerics.tolerantDoubleEquality(0.01)
443
implicit val doubleEq = tolerantDoubleEquality
444
445
3.14159 should equal(3.14 +- 0.01)
446
3.14159 should be(3.14 +- 0.01)
447
```
448
449
### Custom Equality
450
451
```scala { .api }
452
import org.scalactic.Equality
453
454
// Custom equality for case-insensitive string comparison
455
implicit val stringEq = new Equality[String] {
456
def areEqual(left: String, right: Any): Boolean =
457
right match {
458
case str: String => left.toLowerCase == str.toLowerCase
459
case _ => false
460
}
461
}
462
463
"Hello" should equal("HELLO") // Uses custom equality
464
```
465
466
## Inspector Methods
467
468
Apply matchers to all elements of collections.
469
470
```scala { .api }
471
import org.scalatest.Inspectors
472
473
// Apply matcher to all elements
474
all(collection) should be > 0
475
all(collection) should startWith("prefix")
476
477
// Apply matcher to at least one element
478
atLeast(1, collection) should be > 10
479
atMost(3, collection) should be < 5
480
exactly(2, collection) should equal("expected")
481
482
// Apply matcher to between n and m elements
483
between(2, 4, collection) should include("substring")
484
```
485
486
**Inspector Examples:**
487
```scala
488
import org.scalatest.Inspectors
489
490
test("inspector methods") {
491
val numbers = List(1, 2, 3, 4, 5)
492
all(numbers) should be > 0
493
all(numbers) should be <= 5
494
495
atLeast(1, numbers) should be > 3
496
atMost(2, numbers) should be > 4
497
exactly(1, numbers) should equal(3)
498
499
val words = List("hello", "world", "test")
500
all(words) should have length be > 3
501
}