0
# Test Styles
1
2
ScalaTest provides eight different testing styles to accommodate various preferences and use cases. Each style offers a different syntax and organization approach while sharing the same underlying framework capabilities.
3
4
## Capabilities
5
6
### FunSuite Style
7
8
Function-based testing where each test is defined as a function with a descriptive name.
9
10
```scala { .api }
11
import org.scalatest.funsuite.AnyFunSuite
12
import org.scalatest.Tag
13
14
class MyFunSuite extends AnyFunSuite {
15
protected def test(testName: String, testTags: Tag*)(testFun: => Any): Unit
16
protected def ignore(testName: String, testTags: Tag*)(testFun: => Any): Unit
17
}
18
19
// Async version
20
import org.scalatest.funsuite.AsyncFunSuite
21
import scala.concurrent.Future
22
class MyAsyncFunSuite extends AsyncFunSuite {
23
protected def test(testName: String, testTags: Tag*)(testFun: => Future[compatible.Assertion]): Unit
24
}
25
26
// Fixture versions
27
import org.scalatest.funsuite.FixtureAnyFunSuite
28
class MyFixtureFunSuite extends FixtureAnyFunSuite {
29
type FixtureParam = MyFixture
30
def withFixture(test: OneArgTest): Outcome
31
}
32
```
33
34
**Usage Example:**
35
```scala
36
import org.scalatest.funsuite.AnyFunSuite
37
38
class CalculatorSuite extends AnyFunSuite {
39
test("addition should work") {
40
assert(2 + 2 === 4)
41
}
42
43
test("subtraction should work") {
44
assert(4 - 2 === 2)
45
}
46
47
ignore("temporarily disabled test") {
48
// This test will be ignored
49
assert(1 === 2)
50
}
51
}
52
```
53
54
### FlatSpec Style
55
56
BDD-style flat specification with "should" or "must" syntax.
57
58
```scala { .api }
59
import org.scalatest.flatspec.AnyFlatSpec
60
61
class MyFlatSpec extends AnyFlatSpec {
62
behavior of "subject"
63
"it" should "behavior description" in { /* test code */ }
64
"they" should "behavior description" in { /* test code */ }
65
ignore should "ignored behavior" in { /* test code */ }
66
}
67
68
// Async version
69
import org.scalatest.flatspec.AsyncFlatSpec
70
class MyAsyncFlatSpec extends AsyncFlatSpec {
71
"it" should "behavior description" in {
72
Future { assert(true) }
73
}
74
}
75
```
76
77
**Usage Example:**
78
```scala
79
import org.scalatest.flatspec.AnyFlatSpec
80
import org.scalatest.matchers.should.Matchers
81
82
class StackSpec extends AnyFlatSpec with Matchers {
83
behavior of "A Stack"
84
85
it should "pop values in last-in-first-out order" in {
86
val stack = new Stack[Int]
87
stack.push(1)
88
stack.push(2)
89
stack.pop() should be(2)
90
stack.pop() should be(1)
91
}
92
93
it should "throw NoSuchElementException if an empty stack is popped" in {
94
val emptyStack = new Stack[Int]
95
a [NoSuchElementException] should be thrownBy {
96
emptyStack.pop()
97
}
98
}
99
}
100
```
101
102
### WordSpec Style
103
104
Nested specification style using "when" and "should" for organization.
105
106
```scala { .api }
107
import org.scalatest.wordspec.AnyWordSpec
108
109
class MyWordSpec extends AnyWordSpec {
110
"subject" when {
111
"condition" should {
112
"behavior" in { /* test code */ }
113
}
114
}
115
116
"subject" should {
117
"behavior" in { /* test code */ }
118
}
119
}
120
121
// Async version
122
import org.scalatest.wordspec.AsyncWordSpec
123
class MyAsyncWordSpec extends AsyncWordSpec {
124
"subject" should {
125
"behavior" in {
126
Future { assert(true) }
127
}
128
}
129
}
130
```
131
132
**Usage Example:**
133
```scala
134
import org.scalatest.wordspec.AnyWordSpec
135
import org.scalatest.matchers.should.Matchers
136
137
class StackSpec extends AnyWordSpec with Matchers {
138
"A Stack" when {
139
"empty" should {
140
"be empty" in {
141
val stack = new Stack[Int]
142
stack.isEmpty should be(true)
143
}
144
145
"throw NoSuchElementException when popped" in {
146
val stack = new Stack[Int]
147
a [NoSuchElementException] should be thrownBy {
148
stack.pop()
149
}
150
}
151
}
152
153
"non-empty" should {
154
"return the correct size" in {
155
val stack = new Stack[Int]
156
stack.push(1)
157
stack.push(2)
158
stack.size should be(2)
159
}
160
}
161
}
162
}
163
```
164
165
### FreeSpec Style
166
167
Free-form specification style using dash (-) syntax for nesting.
168
169
```scala { .api }
170
import org.scalatest.freespec.AnyFreeSpec
171
172
class MyFreeSpec extends AnyFreeSpec {
173
"description" - {
174
"nested description" - {
175
"test description" in { /* test code */ }
176
}
177
"another test" in { /* test code */ }
178
}
179
}
180
181
// Async version
182
import org.scalatest.freespec.AsyncFreeSpec
183
class MyAsyncFreeSpec extends AsyncFreeSpec {
184
"description" - {
185
"test" in {
186
Future { assert(true) }
187
}
188
}
189
}
190
191
// Path-dependent version (creates new instance for each test)
192
import org.scalatest.freespec.PathAnyFreeSpec
193
class MyPathFreeSpec extends PathAnyFreeSpec {
194
"subject" - {
195
"when condition" - {
196
"should behavior" in {
197
// Each test gets a fresh instance
198
assert(true)
199
}
200
}
201
}
202
}
203
```
204
205
**Usage Example:**
206
```scala
207
import org.scalatest.freespec.AnyFreeSpec
208
import org.scalatest.matchers.should.Matchers
209
210
class StackSpec extends AnyFreeSpec with Matchers {
211
"A Stack" - {
212
"when empty" - {
213
"should be empty" in {
214
val stack = new Stack[Int]
215
stack.isEmpty should be(true)
216
}
217
218
"should throw exception when popped" in {
219
val stack = new Stack[Int]
220
a [NoSuchElementException] should be thrownBy {
221
stack.pop()
222
}
223
}
224
}
225
226
"when containing elements" - {
227
"should not be empty" in {
228
val stack = new Stack[Int]
229
stack.push(1)
230
stack.isEmpty should be(false)
231
}
232
}
233
}
234
}
235
```
236
237
### FeatureSpec Style
238
239
BDD-style feature specification with "feature" and "scenario" keywords.
240
241
```scala { .api }
242
import org.scalatest.featurespec.AnyFeatureSpec
243
244
class MyFeatureSpec extends AnyFeatureSpec {
245
feature("feature description") {
246
scenario("scenario description") { /* test code */ }
247
ignore("ignored scenario") { /* test code */ }
248
}
249
}
250
251
// Async version
252
import org.scalatest.featurespec.AsyncFeatureSpec
253
class MyAsyncFeatureSpec extends AsyncFeatureSpec {
254
feature("feature") {
255
scenario("scenario") {
256
Future { assert(true) }
257
}
258
}
259
}
260
```
261
262
**Usage Example:**
263
```scala
264
import org.scalatest.featurespec.AnyFeatureSpec
265
import org.scalatest.matchers.should.Matchers
266
267
class CalculatorSpec extends AnyFeatureSpec with Matchers {
268
feature("Calculator arithmetic operations") {
269
scenario("User adds two positive numbers") {
270
val calculator = new Calculator
271
val result = calculator.add(2, 3)
272
result should be(5)
273
}
274
275
scenario("User divides by zero") {
276
val calculator = new Calculator
277
a [ArithmeticException] should be thrownBy {
278
calculator.divide(10, 0)
279
}
280
}
281
}
282
283
feature("Calculator memory functions") {
284
scenario("User stores and recalls a value") {
285
val calculator = new Calculator
286
calculator.store(42)
287
calculator.recall() should be(42)
288
}
289
}
290
}
291
```
292
293
### FunSpec Style
294
295
RSpec-style specification with "describe" and "it" blocks.
296
297
```scala { .api }
298
import org.scalatest.funspec.AnyFunSpec
299
300
class MyFunSpec extends AnyFunSpec {
301
describe("subject") {
302
it("behavior description") { /* test code */ }
303
ignore("ignored behavior") { /* test code */ }
304
305
describe("nested subject") {
306
it("nested behavior") { /* test code */ }
307
}
308
}
309
}
310
311
// Async version
312
import org.scalatest.funspec.AsyncFunSpec
313
class MyAsyncFunSpec extends AsyncFunSpec {
314
describe("subject") {
315
it("behavior") {
316
Future { assert(true) }
317
}
318
}
319
}
320
321
// Path-dependent version (creates new instance for each test)
322
import org.scalatest.funspec.PathAnyFunSpec
323
class MyPathFunSpec extends PathAnyFunSpec {
324
describe("subject") {
325
it("behavior description") {
326
// Each test gets a fresh instance
327
assert(true)
328
}
329
330
describe("nested subject") {
331
it("nested behavior") {
332
assert(true)
333
}
334
}
335
}
336
}
337
```
338
339
**Usage Example:**
340
```scala
341
import org.scalatest.funspec.AnyFunSpec
342
import org.scalatest.matchers.should.Matchers
343
344
class StackSpec extends AnyFunSpec with Matchers {
345
describe("A Stack") {
346
describe("when empty") {
347
it("should be empty") {
348
val stack = new Stack[Int]
349
stack.isEmpty should be(true)
350
}
351
352
it("should throw exception when popped") {
353
val stack = new Stack[Int]
354
a [NoSuchElementException] should be thrownBy {
355
stack.pop()
356
}
357
}
358
}
359
360
describe("when it has one item") {
361
it("should have size 1") {
362
val stack = new Stack[Int]
363
stack.push(9)
364
stack.size should be(1)
365
}
366
}
367
}
368
}
369
```
370
371
### PropSpec Style
372
373
Property-based testing style for defining properties that should hold for ranges of data.
374
375
```scala { .api }
376
import org.scalatest.propspec.AnyPropSpec
377
378
class MyPropSpec extends AnyPropSpec {
379
property("property description") { /* test code */ }
380
ignore("ignored property") { /* test code */ }
381
}
382
383
// Async version
384
import org.scalatest.propspec.AsyncPropSpec
385
class MyAsyncPropSpec extends AsyncPropSpec {
386
property("property") {
387
Future { assert(true) }
388
}
389
}
390
```
391
392
**Usage Example:**
393
```scala
394
import org.scalatest.propspec.AnyPropSpec
395
import org.scalatest.matchers.should.Matchers
396
397
class StringSpec extends AnyPropSpec with Matchers {
398
property("string concatenation is associative") {
399
val a = "hello"
400
val b = " "
401
val c = "world"
402
(a + b) + c should equal(a + (b + c))
403
}
404
405
property("string length is additive for concatenation") {
406
val s1 = "hello"
407
val s2 = "world"
408
val combined = s1 + s2
409
combined.length should equal(s1.length + s2.length)
410
}
411
}
412
```
413
414
### RefSpec Style
415
416
Reflection-based specification style where test methods are identified by naming convention.
417
418
```scala { .api }
419
import org.scalatest.refspec.RefSpec
420
421
class MyRefSpec extends RefSpec {
422
// Methods starting with "test" are test methods
423
def `test: description`(): Unit = { /* test code */ }
424
def testDescription(): Unit = { /* test code */ }
425
426
// Methods starting with "ignore" are ignored
427
def `ignore: description`(): Unit = { /* test code */ }
428
}
429
```
430
431
**Usage Example:**
432
```scala
433
import org.scalatest.refspec.RefSpec
434
import org.scalatest.matchers.should.Matchers
435
436
class StackRefSpec extends RefSpec with Matchers {
437
def `test: empty stack should be empty`(): Unit = {
438
val stack = new Stack[Int]
439
stack.isEmpty should be(true)
440
}
441
442
def `test: stack should pop in LIFO order`(): Unit = {
443
val stack = new Stack[Int]
444
stack.push(1)
445
stack.push(2)
446
stack.pop() should be(2)
447
stack.pop() should be(1)
448
}
449
450
def `ignore: temporarily disabled test`(): Unit = {
451
// This test will be ignored
452
assert(false)
453
}
454
}
455
```
456
457
## Fixture Support
458
459
All test styles support fixture variants for managing test resources:
460
461
```scala { .api }
462
// Fixture variants exist for all styles
463
import org.scalatest.funsuite.FixtureAnyFunSuite
464
import org.scalatest.flatspec.FixtureAnyFlatSpec
465
import org.scalatest.wordspec.FixtureAnyWordSpec
466
// ... and so on
467
468
abstract class FixtureTestSuite extends FixtureAnyFunSuite {
469
type FixtureParam = YourFixtureType
470
471
def withFixture(test: OneArgTest): Outcome = {
472
// Setup fixture
473
val fixture = createFixture()
474
try {
475
test(fixture)
476
} finally {
477
// Cleanup fixture
478
cleanupFixture(fixture)
479
}
480
}
481
}
482
```
483
484
## Choosing a Test Style
485
486
- **FunSuite**: Simple function-based tests, good for unit testing
487
- **FlatSpec**: BDD-style with flat organization, good for behavior specification
488
- **WordSpec**: Nested BDD-style with hierarchical organization
489
- **FreeSpec**: Maximum flexibility in organization and nesting
490
- **FeatureSpec**: Feature/scenario BDD style, good for acceptance testing
491
- **FunSpec**: RSpec-style describe/it blocks, familiar to Ruby developers
492
- **PropSpec**: Property-based testing, good for testing invariants
493
- **RefSpec**: Reflection-based, familiar to JUnit users
494
495
All styles can be mixed in a single test suite and share the same assertion and matcher capabilities.
496
497
### Path-Dependent Testing
498
499
FreeSpec and FunSpec support path-dependent variants (`PathAnyFreeSpec`, `PathAnyFunSpec`) that create a new instance of the test class for each test. This provides:
500
501
- **Test Isolation**: Each test runs in a completely fresh instance
502
- **Shared Setup**: Instance variables can be used for test setup without interference
503
- **Stateful Testing**: Safer when tests modify instance state
504
505
Use path-dependent styles when you need strong test isolation or have complex shared setup requirements.