0
# Configuration
1
2
Test configuration classes and metadata types for organizing and controlling test execution. This includes test options, tags for categorizing tests, and source location tracking for error reporting.
3
4
## Capabilities
5
6
### TestOptions - Test Configuration
7
8
Configuration class for customizing individual test behavior including naming, tagging, and execution control.
9
10
```scala { .api }
11
/**
12
* Configuration options for individual tests
13
* @param name The test name
14
* @param tags Set of tags applied to the test
15
* @param location Source code location of the test
16
*/
17
final class TestOptions(val name: String, val tags: Set[Tag], val location: Location) extends Serializable {
18
19
/** Create a new TestOptions with a different name */
20
def withName(newName: String): TestOptions
21
22
/** Create a new TestOptions with different tags */
23
def withTags(newTags: Set[Tag]): TestOptions
24
25
/** Create a new TestOptions with a different location */
26
def withLocation(newLocation: Location): TestOptions
27
28
/** Add a single tag to this test */
29
def tag(t: Tag): TestOptions
30
31
// Convenience methods for common tags
32
/** Mark this test as expected to fail */
33
def fail: TestOptions
34
35
/** Mark this test as potentially flaky */
36
def flaky: TestOptions
37
38
/** Skip this test during execution */
39
def ignore: TestOptions
40
41
/** Mark this test as pending implementation */
42
def pending: TestOptions
43
44
/** Mark this test as pending with a comment */
45
def pending(comment: String): TestOptions
46
47
/** Run only this test (skip all others) */
48
def only: TestOptions
49
}
50
51
/**
52
* Companion object with factory methods
53
*/
54
object TestOptions extends TestOptionsConversions {
55
def apply(name: String)(implicit loc: Location): TestOptions
56
}
57
58
/**
59
* Implicit conversions for convenience
60
*/
61
trait TestOptionsConversions {
62
/** Convert a string to TestOptions with current location */
63
implicit def testOptionsFromString(name: String)(implicit loc: Location): TestOptions
64
}
65
```
66
67
**Usage Examples:**
68
69
```scala
70
class ConfigurationExamples extends FunSuite {
71
test("basic test") {
72
assert(true)
73
}
74
75
test("slow integration test".tag(Slow)) {
76
// This test is marked as slow
77
performIntegrationTest()
78
}
79
80
test("flaky network test".flaky) {
81
// This test may fail intermittently
82
callExternalAPI()
83
}
84
85
test("unimplemented feature".pending) {
86
// This test is not yet implemented
87
}
88
89
test("work in progress".pending("waiting for API changes")) {
90
// Pending with a specific reason
91
}
92
93
test("debug this specific test".only) {
94
// Only this test will run when debugging
95
assert(complexCondition())
96
}
97
98
// Combining multiple tags
99
test(TestOptions("comprehensive test")
100
.tag(Slow)
101
.tag(new Tag("integration"))) {
102
performComprehensiveTest()
103
}
104
}
105
```
106
107
### Test - Test Case Metadata
108
109
Metadata class representing a complete test case with all its configuration and execution details.
110
111
```scala { .api }
112
/**
113
* Complete test case with name, body, tags, and location
114
* @param name The test name
115
* @param body Function that executes the test and returns a Future
116
* @param tags Set of tags applied to this test
117
* @param location Source code location where test is defined
118
*/
119
final class Test(val name: String, val body: () => Future[Any], val tags: Set[Tag], val location: Location) extends Serializable {
120
121
/** Create a new test with a different name */
122
def withName(newName: String): Test
123
124
/** Create a new test with a different body */
125
def withBody(newBody: () => Future[Any]): Test
126
127
/** Create a new test with a transformed body */
128
def withBodyMap(newBody: Future[Any] => Future[Any]): Test
129
130
/** Create a new test with different tags */
131
def withTags(newTags: Set[Tag]): Test
132
133
/** Add a single tag to this test */
134
def tag(newTag: Tag): Test
135
136
/** Create a new test with a different location */
137
def withLocation(newLocation: Location): Test
138
139
/** Get annotations for this test (includes tags and location) */
140
def annotations: Array[Annotation]
141
}
142
```
143
144
### Tag - Test Categories
145
146
Tags for categorizing and controlling test execution behavior.
147
148
```scala { .api }
149
/**
150
* Base tag class for categorizing tests
151
* @param value The tag identifier string
152
*/
153
class Tag(val value: String) extends munit.internal.junitinterface.Tag with Annotation with Serializable
154
```
155
156
**Built-in Tags:**
157
158
```scala { .api }
159
// Pre-defined tags available in the munit package object
160
val Ignore = new Tag("Ignore") // Skip this test
161
val Only = new Tag("Only") // Run only this test
162
val Flaky = new Tag("Flaky") // Test may fail intermittently
163
val Fail = new Tag("Fail") // Test is expected to fail
164
val Pending: Tag with PendingTag = new Tag("Pending") with PendingTag // Test is pending implementation
165
val Slow = new Tag("Slow") // Test is slow running
166
167
/**
168
* Pending tag with custom comment
169
* @param value The comment explaining why test is pending
170
*/
171
case class PendingComment(override val value: String) extends Tag(value) with PendingCommentTag
172
```
173
174
**Usage Examples:**
175
176
```scala
177
class TagExamples extends FunSuite {
178
test("regular test") {
179
assert(true)
180
}
181
182
test("skip this test".tag(Ignore)) {
183
// This test will be skipped
184
fail("Should not run")
185
}
186
187
test("database test".tag(Slow).tag(new Tag("database"))) {
188
// Multiple tags can be applied
189
connectToDatabase()
190
}
191
192
// Custom tags
193
val Integration = new Tag("Integration")
194
val External = new Tag("External")
195
196
test("API integration".tag(Integration).tag(External)) {
197
callExternalAPI()
198
}
199
200
// Environment-specific tags
201
test("linux only test".tag(new Tag("linux"))) {
202
assume(System.getProperty("os.name").toLowerCase.contains("linux"))
203
// Test linux-specific functionality
204
}
205
}
206
```
207
208
### Location - Source Code Location
209
210
Source code location tracking for precise error reporting and IDE integration.
211
212
```scala { .api }
213
/**
214
* Source code location information
215
* @param path The file path where the test is defined
216
* @param line The line number in the file
217
*/
218
final class Location(val path: String, val line: Int) extends Annotation with Serializable {
219
220
/** Extract just the filename from the full path */
221
def filename: String
222
223
/** Format location as "path:line" */
224
override def toString: String
225
}
226
227
/**
228
* Companion object with utility methods
229
*/
230
object Location extends MacroCompat.LocationMacro {
231
/** Empty location placeholder for tests created programmatically */
232
def empty: Location
233
}
234
```
235
236
**Usage Examples:**
237
238
```scala
239
class LocationExamples extends FunSuite {
240
test("location is automatically captured") {
241
// Location is captured via macro at compile time
242
assert(true)
243
}
244
245
// Manual test creation with explicit location
246
val manualTest = new Test(
247
"manual test",
248
() => Future.successful(assert(true)),
249
Set.empty,
250
new Location("MyTest.scala", 42)
251
)
252
}
253
```
254
255
## Tag-Based Test Execution
256
257
### Environment Variables
258
259
MUnit respects several environment variables for controlling test execution:
260
261
- `MUNIT_FLAKY_OK`: Set to allow flaky tests to pass even if they fail
262
- `CI`: Detected automatically to adjust behavior in continuous integration
263
264
### Test Filtering
265
266
Tags can be used with build tools and IDEs to filter which tests run:
267
268
```scala
269
// Run only slow tests
270
sbt 'testOnly -- --include-tags=Slow'
271
272
// Exclude flaky tests
273
sbt 'testOnly -- --exclude-tags=Flaky'
274
275
// Run tests with multiple tags
276
sbt 'testOnly -- --include-tags=Integration,Database'
277
```
278
279
### Custom Tag Patterns
280
281
Create domain-specific tags for your project:
282
283
```scala
284
object TestTags {
285
val Unit = new Tag("Unit")
286
val Integration = new Tag("Integration")
287
val Performance = new Tag("Performance")
288
val Security = new Tag("Security")
289
val UI = new Tag("UI")
290
val API = new Tag("API")
291
}
292
293
class ServiceTests extends FunSuite {
294
import TestTags._
295
296
test("unit test".tag(Unit)) {
297
// Fast unit test
298
}
299
300
test("integration test".tag(Integration).tag(Slow)) {
301
// Slower integration test
302
}
303
304
test("performance benchmark".tag(Performance).tag(Slow)) {
305
// Performance testing
306
}
307
}
308
```
309
310
### Compare - Type-Safe Comparisons
311
312
Type-class that enables type-safe comparisons in MUnit assertions with custom failure handling.
313
314
```scala { .api }
315
/**
316
* Type-class for comparing values in MUnit assertions
317
* Enables type-safe comparisons between related types
318
*/
319
trait Compare[A, B] {
320
321
/** Check if two values are equal according to comparison rules */
322
def isEqual(obtained: A, expected: B): Boolean
323
324
/** Handle comparison failures with custom error messages and diff output */
325
def failEqualsComparison(obtained: A, expected: B, title: Any, assertions: Assertions)(implicit loc: Location, options: DiffOptions): Nothing
326
}
327
328
/**
329
* Companion object providing default comparison implementations
330
*/
331
object Compare extends ComparePriority1 {
332
/** Default comparison using == for any two types */
333
def defaultCompare[A, B]: Compare[A, B]
334
}
335
336
/**
337
* Implicit priority for subtype comparisons
338
*/
339
trait ComparePriority1 extends ComparePriority2 {
340
/** Allow comparison when A is a subtype of B */
341
implicit def compareSubtypeWithSupertype[A, B](implicit ev: A <:< B): Compare[A, B]
342
}
343
344
/**
345
* Implicit priority for supertype comparisons
346
*/
347
trait ComparePriority2 {
348
/** Allow comparison when B is a subtype of A */
349
implicit def compareSupertypeWithSubtype[A, B](implicit ev: A <:< B): Compare[B, A]
350
}
351
```
352
353
**Usage Examples:**
354
355
```scala
356
// Custom comparison for domain objects
357
implicit val userCompare: Compare[User, User] = new Compare[User, User] {
358
def isEqual(obtained: User, expected: User): Boolean =
359
obtained.id == expected.id && obtained.email == expected.email
360
361
def failEqualsComparison(obtained: User, expected: User, title: Any, assertions: Assertions)(implicit loc: Location, options: DiffOptions): Nothing =
362
assertions.failComparison(s"Users not equal: $title", obtained, expected)
363
}
364
365
class UserTests extends FunSuite {
366
test("user equality") {
367
val user1 = User(1, "alice@example.com", "Alice")
368
val user2 = User(1, "alice@example.com", "Alice Smith") // Different name
369
assertEquals(user1, user2) // Uses custom comparison (ignores name)
370
}
371
}
372
```
373
374
### Printable - Custom Pretty-Printing
375
376
Interface for customizing how values are displayed in test failure messages.
377
378
```scala { .api }
379
/**
380
* Interface for objects that can customize their printed representation
381
*/
382
trait Printable {
383
/** Append custom representation to a StringBuilder */
384
def print(out: StringBuilder, indent: Int): Unit
385
}
386
```
387
388
**Usage Examples:**
389
390
```scala
391
case class ComplexData(values: Map[String, Any]) extends Printable {
392
def print(out: StringBuilder, indent: Int): Unit = {
393
out.append("ComplexData(\n")
394
values.foreach { case (key, value) =>
395
out.append(" " * (indent + 1))
396
out.append(s"$key = $value\n")
397
}
398
out.append(" " * indent)
399
out.append(")")
400
}
401
}
402
403
class PrintableTests extends FunSuite {
404
test("complex data comparison") {
405
val data1 = ComplexData(Map("x" -> 1, "y" -> 2))
406
val data2 = ComplexData(Map("x" -> 1, "y" -> 3))
407
408
// Custom printing will be used in failure message
409
assertEquals(data1, data2)
410
}
411
}
412
```
413
414
### MUnitRunner - Test Framework Integration
415
416
JUnit runner that enables MUnit integration with IDEs and build tools.
417
418
```scala { .api }
419
/**
420
* JUnit runner for MUnit test suites
421
* Automatically applied to Suite classes via @RunWith annotation
422
*/
423
class MUnitRunner(val cls: Class[_ <: Suite], newInstance: () => Suite) extends Runner
424
425
/**
426
* Companion object with runner utilities
427
*/
428
object MUnitRunner {
429
/** Create a runner for a suite class */
430
def apply(cls: Class[_ <: Suite]): MUnitRunner
431
}
432
```
433
434
**Usage:**
435
436
```scala
437
// Automatically applied to all Suite subclasses
438
@RunWith(classOf[MUnitRunner])
439
abstract class Suite extends PlatformSuite {
440
// Suite implementation
441
}