0
# Test Execution
1
2
ScalaTest provides comprehensive test execution capabilities including programmatic execution, command-line runners, build tool integration, and extensive configuration options. The framework supports parallel execution, filtering, reporting, and integration with various development environments.
3
4
## Capabilities
5
6
### Programmatic Test Execution
7
8
Execute tests directly from Scala code with full control over configuration.
9
10
```scala { .api }
11
import org.scalatest._
12
13
// Main execution entry point
14
object run {
15
def main(args: Array[String]): Unit
16
def apply(
17
suite: Suite,
18
testName: String = null,
19
configMap: ConfigMap = ConfigMap.empty,
20
color: Boolean = true,
21
durations: Boolean = false,
22
shortstacks: Boolean = false,
23
fullstacks: Boolean = false,
24
stats: Boolean = false
25
): Unit
26
}
27
28
// Suite execution methods
29
trait Suite {
30
def run(testName: Option[String], args: Args): Status
31
def execute(
32
testName: Option[String] = None,
33
configMap: ConfigMap = ConfigMap.empty,
34
color: Boolean = true,
35
durations: Boolean = false,
36
shortstacks: Boolean = false,
37
fullstacks: Boolean = false,
38
stats: Boolean = false,
39
reporter: Reporter = new StandardOutReporter,
40
stopper: Stopper = Stopper.default,
41
filter: Filter = Filter(),
42
tracker: Tracker = new Tracker,
43
chosenStyles: Set[String] = Set.empty,
44
runTestInNewInstance: Boolean = false,
45
distributor: Option[Distributor] = None,
46
summaryCounter: SummaryCounter = new SummaryCounter
47
): Status
48
}
49
```
50
51
**Programmatic Execution Examples:**
52
```scala
53
import org.scalatest._
54
import org.scalatest.funsuite.AnyFunSuite
55
56
class MySuite extends AnyFunSuite {
57
test("example test") {
58
assert(1 + 1 === 2)
59
}
60
}
61
62
// Simple execution
63
run(new MySuite)
64
65
// Execution with configuration
66
val suite = new MySuite
67
suite.execute(
68
configMap = ConfigMap("env" -> "test"),
69
color = true,
70
durations = true,
71
stats = true
72
)
73
74
// Execute specific test
75
suite.execute(testName = Some("example test"))
76
```
77
78
### Command-Line Runner
79
80
Execute tests from the command line with extensive configuration options.
81
82
```scala { .api }
83
import org.scalatest.tools._
84
85
object Runner {
86
def main(args: Array[String]): Unit
87
def run(args: Array[String]): Boolean
88
}
89
90
// Common command-line arguments:
91
// -o : StandardOutReporter
92
// -e : StandardErrReporter
93
// -f <filename> : FileReporter
94
// -u <directory> : JunitXmlReporter
95
// -h <filename> : HtmlReporter
96
// -n <tag> : Include only tests with tag
97
// -l <tag> : Exclude tests with tag
98
// -s <classname> : Run specific suite
99
// -j <classname> : Run with JUnitRunner
100
// -m <classname> : Run specific member (test)
101
// -w <package> : Wildcard package discovery
102
// -q : Suppress reminder message
103
// -S : Enable short stack traces
104
// -F : Enable full stack traces
105
// -T : Show durations
106
// -C : Disable ANSI color
107
// -D : Show all durations
108
```
109
110
**Command-Line Examples:**
111
```bash
112
# Run all tests with console output
113
scala -cp <classpath> org.scalatest.tools.Runner -o
114
115
# Run specific suite
116
scala -cp <classpath> org.scalatest.tools.Runner -s com.example.MySuite -o
117
118
# Run tests with HTML report
119
scala -cp <classpath> org.scalatest.tools.Runner -o -h reports/test-results.html
120
121
# Run tests with JUnit XML output
122
scala -cp <classpath> org.scalatest.tools.Runner -o -u target/test-reports
123
124
# Run tests with specific tags
125
scala -cp <classpath> org.scalatest.tools.Runner -n FastTest -l SlowTest -o
126
127
# Run with parallel execution and durations
128
scala -cp <classpath> org.scalatest.tools.Runner -P -T -o
129
```
130
131
### Test Configuration
132
133
Configure test execution behavior through Args and ConfigMap.
134
135
```scala { .api }
136
// Test execution arguments
137
case class Args(
138
reporter: Reporter,
139
stopper: Stopper,
140
filter: Filter,
141
configMap: ConfigMap,
142
distributor: Option[Distributor],
143
tracker: Tracker,
144
chosenStyles: Set[String],
145
runTestInNewInstance: Boolean,
146
distributedTestSorter: Option[DistributedTestSorter],
147
summaryCounter: SummaryCounter
148
)
149
150
// Configuration map for passing data to tests
151
type ConfigMap = Map[String, Any]
152
object ConfigMap {
153
def empty: ConfigMap = Map.empty
154
def apply(entries: (String, Any)*): ConfigMap = Map(entries: _*)
155
}
156
157
// Test filtering
158
class Filter(
159
tagsToInclude: Option[Set[String]] = None,
160
tagsToExclude: Set[String] = Set.empty,
161
excludeNestedSuites: Boolean = false,
162
dynaTags: DynaTags = DynaTags(Map.empty, Map.empty)
163
)
164
165
// Execution control
166
trait Stopper {
167
def stopRequested: Boolean
168
def requestStop(): Unit
169
}
170
```
171
172
**Configuration Examples:**
173
```scala
174
import org.scalatest._
175
176
// Custom configuration map
177
val config = ConfigMap(
178
"db.url" -> "jdbc:h2:mem:test",
179
"timeout" -> 30,
180
"env" -> "test"
181
)
182
183
// Custom filter - include FastTest, exclude SlowTest
184
val filter = Filter(
185
tagsToInclude = Some(Set("FastTest")),
186
tagsToExclude = Set("SlowTest")
187
)
188
189
// Custom args with configuration
190
val args = Args(
191
reporter = new StandardOutReporter,
192
stopper = Stopper.default,
193
filter = filter,
194
configMap = config,
195
distributor = None,
196
tracker = new Tracker,
197
chosenStyles = Set.empty,
198
runTestInNewInstance = false,
199
distributedTestSorter = None,
200
summaryCounter = new SummaryCounter
201
)
202
203
// Use configuration in test
204
class ConfigurableTest extends AnyFunSuite {
205
test("uses configuration") {
206
val dbUrl = testOptions.configMap.getOrElse("db.url", "default-url")
207
assert(dbUrl === "jdbc:h2:mem:test")
208
}
209
}
210
```
211
212
### Test Reporters
213
214
Various output formats for test results.
215
216
```scala { .api }
217
import org.scalatest.tools._
218
219
// Base reporter trait
220
trait Reporter {
221
def apply(event: Event): Unit
222
}
223
224
// Built-in reporters
225
class StandardOutReporter extends Reporter
226
class StandardErrReporter extends Reporter
227
class FileReporter(fileName: String) extends Reporter
228
class HtmlReporter(directory: String) extends Reporter
229
class JunitXmlReporter(directory: String) extends Reporter
230
class XmlReporter(fileName: String) extends Reporter
231
class MemoryReporter extends Reporter {
232
def eventsReceived: IndexedSeq[Event]
233
}
234
235
// Composite reporter for multiple outputs
236
class MultipleReporter(reporters: Reporter*) extends Reporter
237
238
// Graphic reporter for GUI output
239
class GraphicReporter extends Reporter
240
```
241
242
**Reporter Examples:**
243
```scala
244
import org.scalatest.tools._
245
246
// Multiple reporters
247
val reporters = List(
248
new StandardOutReporter,
249
new HtmlReporter("target/test-reports"),
250
new JunitXmlReporter("target/junit-reports"),
251
new FileReporter("test-results.txt")
252
)
253
254
val multiReporter = new MultipleReporter(reporters: _*)
255
256
// Memory reporter for programmatic access to results
257
val memoryReporter = new MemoryReporter
258
suite.execute(reporter = memoryReporter)
259
260
// Access collected events
261
val events = memoryReporter.eventsReceived
262
val failures = events.collect { case tf: TestFailed => tf }
263
val successes = events.collect { case ts: TestSucceeded => ts }
264
```
265
266
### Test Events
267
268
Events generated during test execution for reporting and monitoring.
269
270
```scala { .api }
271
import org.scalatest.events._
272
273
// Base event types
274
sealed abstract class Event {
275
val ordinal: Ordinal
276
val presenter: Option[Presenter]
277
val location: Option[Location]
278
val message: String
279
val formatter: Option[Formatter]
280
val payload: Option[Any]
281
val threadName: String
282
val timeStamp: Long
283
}
284
285
// Test lifecycle events
286
case class RunStarting(
287
testCount: Int,
288
configMap: ConfigMap,
289
formatter: Option[Formatter],
290
location: Option[Location],
291
payload: Option[Any],
292
threadName: String,
293
timeStamp: Long
294
) extends Event
295
296
case class SuiteStarting(
297
suiteName: String,
298
suiteId: String,
299
suiteClassName: Option[String],
300
formatter: Option[Formatter],
301
location: Option[Location],
302
rerunnable: Option[String],
303
payload: Option[Any],
304
threadName: String,
305
timeStamp: Long
306
) extends Event
307
308
case class TestStarting(
309
suiteName: String,
310
suiteId: String,
311
suiteClassName: Option[String],
312
testName: String,
313
testText: String,
314
formatter: Option[Formatter],
315
location: Option[Location],
316
rerunnable: Option[String],
317
payload: Option[Any],
318
threadName: String,
319
timeStamp: Long
320
) extends Event
321
322
// Test result events
323
case class TestSucceeded(
324
suiteName: String,
325
suiteId: String,
326
suiteClassName: Option[String],
327
testName: String,
328
testText: String,
329
recordedEvents: IndexedSeq[RecordableEvent],
330
duration: Option[Long],
331
formatter: Option[Formatter],
332
location: Option[Location],
333
rerunnable: Option[String],
334
payload: Option[Any],
335
threadName: String,
336
timeStamp: Long
337
) extends Event
338
339
case class TestFailed(
340
message: String,
341
suiteName: String,
342
suiteId: String,
343
suiteClassName: Option[String],
344
testName: String,
345
testText: String,
346
recordedEvents: IndexedSeq[RecordableEvent],
347
throwable: Option[Throwable],
348
duration: Option[Long],
349
formatter: Option[Formatter],
350
location: Option[Location],
351
rerunnable: Option[String],
352
payload: Option[Any],
353
threadName: String,
354
timeStamp: Long
355
) extends Event
356
357
case class TestIgnored(
358
suiteName: String,
359
suiteId: String,
360
suiteClassName: Option[String],
361
testName: String,
362
testText: String,
363
formatter: Option[Formatter],
364
location: Option[Location],
365
payload: Option[Any],
366
threadName: String,
367
timeStamp: Long
368
) extends Event
369
370
case class TestPending(
371
suiteName: String,
372
suiteId: String,
373
suiteClassName: Option[String],
374
testName: String,
375
testText: String,
376
recordedEvents: IndexedSeq[RecordableEvent],
377
duration: Option[Long],
378
formatter: Option[Formatter],
379
location: Option[Location],
380
payload: Option[Any],
381
threadName: String,
382
timeStamp: Long
383
) extends Event
384
385
case class TestCanceled(
386
message: String,
387
suiteName: String,
388
suiteId: String,
389
suiteClassName: Option[String],
390
testName: String,
391
testText: String,
392
recordedEvents: IndexedSeq[RecordableEvent],
393
throwable: Option[Throwable],
394
duration: Option[Long],
395
formatter: Option[Formatter],
396
location: Option[Location],
397
payload: Option[Any],
398
threadName: String,
399
timeStamp: Long
400
) extends Event
401
```
402
403
### Status and Results
404
405
Track test execution progress and results.
406
407
```scala { .api }
408
// Execution status
409
sealed trait Status {
410
def isCompleted: Boolean
411
def succeeds(): Boolean
412
def unreportedException: Option[Throwable]
413
def whenCompleted(f: Boolean => Unit): Unit
414
def waitUntilCompleted(): Unit
415
}
416
417
// Status implementations
418
case object SucceededStatus extends Status {
419
val isCompleted = true
420
def succeeds() = true
421
val unreportedException = None
422
}
423
424
case class FailedStatus(ex: Throwable) extends Status {
425
val isCompleted = true
426
def succeeds() = false
427
val unreportedException = Some(ex)
428
}
429
430
class StatefulStatus extends Status {
431
def setCompleted(): Unit
432
def setFailed(ex: Throwable): Unit
433
def waitUntilCompleted(): Unit
434
}
435
436
// Result counting
437
class SummaryCounter {
438
def testsSucceededCount: Int
439
def testsFailedCount: Int
440
def testsIgnoredCount: Int
441
def testsPendingCount: Int
442
def testsCanceledCount: Int
443
def suitesCompletedCount: Int
444
def suitesAbortedCount: Int
445
def scopesPendingCount: Int
446
}
447
```
448
449
### Parallel Execution
450
451
Execute tests in parallel for better performance.
452
453
```scala { .api }
454
// Distributor for parallel execution
455
trait Distributor {
456
def apply(suite: Suite, args: Args): Status
457
def apply(suite: Suite, tracker: Tracker): Unit
458
}
459
460
// Parallel execution configuration
461
class ParallelTestExecution extends Distributor
462
463
// Suite-level parallel execution
464
trait ParallelTestExecution { this: Suite =>
465
// Mixed into suite to enable parallel test execution
466
}
467
468
// Async execution for Future-based tests
469
trait AsyncTestExecution { this: Suite =>
470
// Mixed into suite to enable async test execution
471
}
472
```
473
474
**Parallel Execution Examples:**
475
```scala
476
import org.scalatest._
477
import org.scalatest.funsuite.AnyFunSuite
478
479
// Enable parallel execution for suite
480
class ParallelSuite extends AnyFunSuite with ParallelTestExecution {
481
test("parallel test 1") {
482
// This test can run in parallel with others
483
Thread.sleep(100)
484
assert(true)
485
}
486
487
test("parallel test 2") {
488
// This test can run in parallel with others
489
Thread.sleep(100)
490
assert(true)
491
}
492
}
493
494
// Command-line parallel execution
495
// scala -cp <classpath> org.scalatest.tools.Runner -P -o
496
```
497
498
### Build Tool Integration
499
500
Integration with SBT, Maven, and other build tools.
501
502
```scala { .api }
503
// SBT Framework implementation
504
class Framework extends sbt.testing.Framework {
505
def name(): String = "ScalaTest"
506
def fingerprints(): Array[sbt.testing.Fingerprint]
507
def runner(args: Array[String], remoteArgs: Array[String], testClassLoader: ClassLoader): sbt.testing.Runner
508
}
509
510
// JUnit integration
511
class JUnitRunner(clazz: Class[_ <: Suite]) extends org.junit.runner.Runner {
512
def run(notifier: RunNotifier): Unit
513
def getDescription: Description
514
}
515
516
// TestNG integration
517
class TestNGSuite extends Suite with TestNGSuiteLike
518
```
519
520
**SBT Integration Example:**
521
```scala
522
// build.sbt
523
libraryDependencies += "org.scalatest" %% "scalatest" % "3.2.19" % Test
524
525
// SBT test command runs ScalaTest
526
// sbt test
527
528
// SBT test configuration
529
Test / testOptions += Tests.Argument(TestFrameworks.ScalaTest, "-o")
530
Test / testOptions += Tests.Argument(TestFrameworks.ScalaTest, "-h", "target/test-reports")
531
532
// Parallel execution in SBT
533
Test / parallelExecution := true
534
```
535
536
### Custom Test Discovery
537
538
Discover and run tests dynamically.
539
540
```scala { .api }
541
// Suite discovery
542
object SuiteDiscoveryHelper {
543
def discoverSuiteNames(
544
loader: ClassLoader,
545
packageNames: List[String],
546
accessibleSuites: Set[String],
547
wildcard: Boolean,
548
runpathClassLoader: ClassLoader
549
): Set[String]
550
}
551
552
// Dynamic suite creation
553
trait Suite {
554
def nestedSuites: IndexedSeq[Suite]
555
def run(testName: Option[String], args: Args): Status
556
}
557
```
558
559
### Shell Integration
560
561
Interactive shell for running tests in REPL environments.
562
563
```scala { .api }
564
// Shell configuration objects (JVM only)
565
lazy val color: Shell // Enable colored output
566
lazy val durations: Shell // Show test durations
567
lazy val shortstacks: Shell // Show short stack traces
568
lazy val fullstacks: Shell // Show full stack traces
569
lazy val stats: Shell // Show statistics
570
lazy val nocolor: Shell // Disable colored output
571
lazy val nodurations: Shell // Hide test durations
572
lazy val nostacks: Shell // Hide stack traces
573
lazy val nostats: Shell // Hide statistics
574
575
// Shell trait
576
trait Shell {
577
def run(testName: String, reporter: Reporter, stopper: Stopper,
578
filter: Filter, configMap: ConfigMap, distributor: Option[Distributor],
579
tracker: Tracker): Unit
580
}
581
```
582
583
**Shell Examples:**
584
```scala
585
// In Scala REPL
586
import org.scalatest._
587
588
// Run with colored output and durations
589
color.durations.run(new MySuite)
590
591
// Run specific test
592
run(new MySuite, "specific test name")
593
594
// Run with custom configuration
595
run(new MySuite, configMap = ConfigMap("env" -> "test"))
596
```