0
# Test Execution
1
2
The test execution system runs ZIO test specifications and handles platform-specific execution models. It bridges ZIO's effect-based testing system with SBT's imperative test execution model, managing ZIO runtime lifecycle and test result collection.
3
4
## Capabilities
5
6
### BaseTestTask
7
8
Abstract base class that provides the core test execution logic shared across all platforms. It handles ZIO runtime management, test specification loading, and result reporting.
9
10
```scala { .api }
11
/**
12
* Base implementation for ZIO test task execution
13
* Provides core functionality shared across all platforms
14
*/
15
abstract class BaseTestTask(
16
taskDef0: sbt.testing.TaskDef,
17
val testClassLoader: ClassLoader,
18
val sendSummary: SendSummary,
19
val args: zio.test.TestArgs
20
) extends sbt.testing.Task {
21
22
/** Returns the task definition provided by SBT */
23
final def taskDef(): sbt.testing.TaskDef
24
25
/** The class loader used for loading test specifications */
26
val testClassLoader: ClassLoader
27
28
/** Function for transmitting test summaries */
29
val sendSummary: SendSummary
30
31
/** Parsed test arguments from command line */
32
val args: zio.test.TestArgs
33
34
/**
35
* Executes the test task (JVM platforms)
36
* @param eventHandler Handles test events for SBT reporting
37
* @param loggers Array of SBT loggers for output
38
* @return Array of additional tasks to run (typically empty)
39
*/
40
def execute(
41
eventHandler: sbt.testing.EventHandler,
42
loggers: Array[sbt.testing.Logger]
43
): Array[sbt.testing.Task]
44
45
/** Returns empty array - ZIO tests don't use tags */
46
def tags(): Array[String]
47
}
48
```
49
50
**Protected Members:**
51
52
```scala { .api }
53
/**
54
* Lazily loaded test specification instance
55
* Uses reflection to load the object specified by taskDef
56
*/
57
protected lazy val specInstance: zio.test.AbstractRunnableSpec
58
59
/**
60
* Core test execution logic as a ZIO effect
61
* @param eventHandler SBT event handler for reporting results
62
* @return ZIO effect that runs the test and reports results
63
*/
64
protected def run(
65
eventHandler: sbt.testing.EventHandler
66
): zio.ZIO[zio.test.TestLogger with zio.clock.Clock, Throwable, Unit]
67
68
/**
69
* Creates ZIO layer with test logging and clock services
70
* @param loggers SBT loggers to integrate with ZIO's TestLogger
71
* @return ZIO layer providing TestLogger and Clock services
72
*/
73
protected def sbtTestLayer(
74
loggers: Array[sbt.testing.Logger]
75
): zio.Layer[Nothing, zio.test.TestLogger with zio.clock.Clock]
76
```
77
78
### ZTestRunner (JVM Platform)
79
80
JVM-specific test runner implementation that provides synchronous test execution with thread-safe summary collection.
81
82
```scala { .api }
83
/**
84
* JVM-specific test runner with synchronous execution
85
* Collects summaries in thread-safe manner for final reporting
86
*/
87
class ZTestRunner(
88
val args: Array[String],
89
val remoteArgs: Array[String],
90
testClassLoader: ClassLoader
91
) extends sbt.testing.Runner {
92
93
/** Command line arguments passed to the test framework */
94
val args: Array[String]
95
96
/** Remote arguments for distributed testing */
97
val remoteArgs: Array[String]
98
99
/** Thread-safe collection of test summaries */
100
val summaries: java.util.concurrent.atomic.AtomicReference[Vector[zio.test.Summary]]
101
102
/** Summary transmission function that collects summaries locally */
103
val sendSummary: SendSummary
104
105
/**
106
* Creates test tasks from task definitions
107
* @param defs Array of task definitions discovered by SBT
108
* @return Array of ZTestTask instances ready for execution
109
*/
110
def tasks(defs: Array[sbt.testing.TaskDef]): Array[sbt.testing.Task]
111
112
/**
113
* Returns final test execution summary
114
* Called by SBT after all tests complete
115
* @return Formatted summary string with test results
116
*/
117
def done(): String
118
}
119
```
120
121
**Usage Example:**
122
123
```scala
124
// Automatically created by ZTestFramework - not used directly
125
// When SBT runs tests, it:
126
// 1. Calls ZTestFramework.runner() to create ZTestRunner
127
// 2. Calls runner.tasks() to get test tasks
128
// 3. Executes each task via task.execute()
129
// 4. Calls runner.done() for final summary
130
131
// Example test task execution flow:
132
val runner = new ZTestRunner(args, remoteArgs, classLoader)
133
val tasks = runner.tasks(discoveredTaskDefs)
134
tasks.foreach(_.execute(eventHandler, loggers))
135
val summary = runner.done()
136
```
137
138
### ZTestTask (JVM Platform)
139
140
JVM-specific test task implementation that extends `BaseTestTask` with synchronous execution.
141
142
```scala { .api }
143
/**
144
* JVM-specific test task implementation
145
* Provides synchronous test execution using ZIO runtime
146
*/
147
class ZTestTask(
148
taskDef: sbt.testing.TaskDef,
149
testClassLoader: ClassLoader,
150
sendSummary: SendSummary,
151
testArgs: zio.test.TestArgs
152
) extends BaseTestTask(taskDef, testClassLoader, sendSummary, testArgs)
153
```
154
155
### ZTestRunner (JavaScript/Native Platforms)
156
157
Base runner implementation for JavaScript and Native platforms that supports asynchronous execution and inter-process communication.
158
159
```scala { .api }
160
/**
161
* Base runner for JS/Native platforms with async execution support
162
* Handles serialization for inter-process communication
163
*/
164
sealed abstract class ZTestRunner(
165
val args: Array[String],
166
val remoteArgs: Array[String],
167
testClassLoader: ClassLoader,
168
runnerType: String
169
) extends sbt.testing.Runner {
170
171
/** Abstract summary transmission function - implemented by subclasses */
172
def sendSummary: SendSummary
173
174
/** Mutable buffer for collecting test summaries */
175
val summaries: scala.collection.mutable.Buffer[zio.test.Summary]
176
177
/**
178
* Creates test tasks from task definitions
179
* @param defs Array of task definitions discovered by SBT
180
* @return Array of ZTestTask instances for async execution
181
*/
182
def tasks(defs: Array[sbt.testing.TaskDef]): Array[sbt.testing.Task]
183
184
/**
185
* Returns final test execution summary
186
* @return Formatted summary string with test results
187
*/
188
def done(): String
189
190
/**
191
* Handles serialized summary messages from slave processes
192
* @param summary Serialized summary string
193
* @return Optional response message
194
*/
195
def receiveMessage(summary: String): Option[String]
196
197
/**
198
* Serializes a task for inter-process communication
199
* @param task Task to serialize
200
* @param serializer Function to serialize TaskDef
201
* @return Serialized task string
202
*/
203
def serializeTask(task: sbt.testing.Task, serializer: sbt.testing.TaskDef => String): String
204
205
/**
206
* Deserializes a task from inter-process communication
207
* @param task Serialized task string
208
* @param deserializer Function to deserialize TaskDef
209
* @return Deserialized task instance
210
*/
211
def deserializeTask(task: String, deserializer: String => sbt.testing.TaskDef): sbt.testing.Task
212
}
213
```
214
215
### ZMasterTestRunner
216
217
Master runner implementation for multi-process test execution on JS/Native platforms.
218
219
```scala { .api }
220
/**
221
* Master runner for multi-process execution
222
* Collects summaries locally when running single-process tests
223
*/
224
class ZMasterTestRunner(
225
args: Array[String],
226
remoteArgs: Array[String],
227
testClassLoader: ClassLoader
228
) extends ZTestRunner(args, remoteArgs, testClassLoader, "master") {
229
230
/** Local summary collection implementation */
231
val sendSummary: SendSummary
232
}
233
```
234
235
### ZSlaveTestRunner
236
237
Slave runner implementation that transmits results to master process.
238
239
```scala { .api }
240
/**
241
* Slave runner for distributed execution
242
* Transmits summaries to master process via provided send function
243
*/
244
class ZSlaveTestRunner(
245
args: Array[String],
246
remoteArgs: Array[String],
247
testClassLoader: ClassLoader,
248
val sendSummary: SendSummary
249
) extends ZTestRunner(args, remoteArgs, testClassLoader, "slave")
250
```
251
252
### ZTestTask (JavaScript/Native Platforms)
253
254
Asynchronous test task implementation for JS/Native platforms with continuation-based execution.
255
256
```scala { .api }
257
/**
258
* Asynchronous test task for JS/Native platforms
259
* Uses continuation-based execution model
260
*/
261
class ZTestTask(
262
taskDef: sbt.testing.TaskDef,
263
testClassLoader: ClassLoader,
264
runnerType: String,
265
sendSummary: SendSummary,
266
testArgs: zio.test.TestArgs
267
) extends BaseTestTask(taskDef, testClassLoader, sendSummary, testArgs) {
268
269
/**
270
* Executes test asynchronously with continuation
271
* @param eventHandler SBT event handler for reporting
272
* @param loggers Array of SBT loggers
273
* @param continuation Callback invoked when execution completes
274
*/
275
def execute(
276
eventHandler: sbt.testing.EventHandler,
277
loggers: Array[sbt.testing.Logger],
278
continuation: Array[sbt.testing.Task] => Unit
279
): Unit
280
}
281
```
282
283
### ZTestTaskPolicy
284
285
Policy interface for customizing test task execution and merging behavior.
286
287
```scala { .api }
288
/**
289
* Abstract policy for merging and customizing test tasks
290
* Allows customization of test execution behavior
291
*/
292
abstract class ZTestTaskPolicy {
293
/**
294
* Merges ZIO test tasks according to policy
295
* @param zioTasks Array of ZIO test tasks to merge
296
* @return Array of tasks to execute (may be modified or filtered)
297
*/
298
def merge(zioTasks: Array[ZTestTask]): Array[sbt.testing.Task]
299
}
300
301
/**
302
* Default policy implementation that passes through tasks unchanged
303
*/
304
class ZTestTaskPolicyDefaultImpl extends ZTestTaskPolicy {
305
def merge(zioTasks: Array[ZTestTask]): Array[sbt.testing.Task] = zioTasks.toArray
306
}
307
```
308
309
**Custom Policy Example:**
310
311
```scala
312
// Custom policy that groups tests for batch execution
313
class BatchingTestPolicy extends ZTestTaskPolicy {
314
def merge(zioTasks: Array[ZTestTask]): Array[sbt.testing.Task] = {
315
// Custom logic to group or filter tasks
316
// Could implement parallel execution, test ordering, etc.
317
zioTasks.toArray
318
}
319
}
320
321
// Usage via system property or test args
322
// -Dzio.test.sbt.testTaskPolicy=com.example.BatchingTestPolicy
323
```
324
325
## Test Execution Flow
326
327
The test execution process follows these steps:
328
329
1. **Task Creation**: SBT creates `TaskDef` instances for discovered test specifications
330
2. **Runner Creation**: Framework creates appropriate runner (JVM/Master/Slave) based on platform
331
3. **Task Generation**: Runner creates `ZTestTask` instances from `TaskDef`s
332
4. **Policy Application**: Task policy merges/filters tasks as needed
333
5. **Test Execution**: Each task:
334
- Loads the test specification using reflection
335
- Creates ZIO runtime with test logger layer
336
- Executes the ZIO test specification
337
- Converts results to SBT events
338
- Transmits summary via `SendSummary`
339
6. **Summary Collection**: Runner collects summaries from all tasks
340
7. **Final Reporting**: Runner returns formatted summary via `done()`
341
342
The system handles platform differences transparently while maintaining consistent behavior across JVM, JavaScript, and Native platforms.