0
# ZIO Test SBT
1
2
SBT test framework integration for ZIO Test, providing the necessary infrastructure to run ZIO-based tests within SBT build environments across JVM, JavaScript, and Native platforms. This library implements the SBT testing interface protocols and provides test runners, event handlers, and summary reporting capabilities for ZIO Test specifications.
3
4
## Package Information
5
6
- **Package Name**: zio-test-sbt
7
- **Package Group**: dev.zio
8
- **Language**: Scala
9
- **Platforms**: JVM, JavaScript (ScalaJS), Native (Scala Native)
10
- **Installation**: Add to `build.sbt`: `libraryDependencies += "dev.zio" %% "zio-test-sbt" % "1.0.18"`
11
12
## Core Imports
13
14
```scala
15
import zio.test.sbt._
16
```
17
18
For SBT framework integration:
19
20
```scala
21
import zio.test.sbt.ZTestFramework
22
```
23
24
For custom test tasks:
25
26
```scala
27
import zio.test.sbt.{BaseTestTask, SendSummary}
28
```
29
30
## Basic Usage
31
32
The framework is automatically detected by SBT when included as a dependency. ZIO Test specs extending `AbstractRunnableSpec` are automatically discovered and executed:
33
34
```scala
35
import zio.test._
36
import zio.test.Assertion._
37
38
object MyTestSuite extends DefaultRunnableSpec {
39
def spec = suite("MyTestSuite")(
40
test("basic test") {
41
assert(1 + 1)(equalTo(2))
42
},
43
test("async test") {
44
for {
45
result <- ZIO.succeed(42)
46
} yield assert(result)(equalTo(42))
47
}
48
)
49
}
50
```
51
52
## Architecture
53
54
The library follows SBT's testing framework protocol with ZIO-specific implementations:
55
56
- **ZTestFramework**: Entry point that SBT uses to discover and execute tests
57
- **ZTestRunner**: Platform-specific test runners that manage test execution
58
- **BaseTestTask**: Base class for individual test tasks that run ZIO specs
59
- **ZTestEvent**: SBT-compatible events generated from ZIO test results
60
- **SummaryProtocol**: Serialization for distributed testing (JS/Native platforms)
61
62
## Capabilities
63
64
### Framework Integration
65
66
The main entry point for SBT integration.
67
68
#### JVM Framework
69
70
```scala { .api }
71
final class ZTestFramework extends sbt.testing.Framework {
72
override val name: String
73
val fingerprints: Array[sbt.testing.Fingerprint]
74
def runner(args: Array[String], remoteArgs: Array[String], testClassLoader: ClassLoader): ZTestRunner
75
}
76
```
77
78
#### JavaScript/Native Framework
79
80
```scala { .api }
81
final class ZTestFramework extends sbt.testing.Framework {
82
override def name(): String
83
override def fingerprints(): Array[sbt.testing.Fingerprint]
84
def runner(args: Array[String], remoteArgs: Array[String], testClassLoader: ClassLoader): sbt.testing.Runner
85
def slaveRunner(
86
args: Array[String],
87
remoteArgs: Array[String],
88
testClassLoader: ClassLoader,
89
send: String => Unit
90
): sbt.testing.Runner
91
}
92
```
93
94
The framework provides:
95
- Automatic discovery of ZIO test specifications via `RunnableSpecFingerprint`
96
- Cross-platform support (JVM, JS, Native)
97
- Distributed testing support for JS/Native platforms via master/slave runner architecture
98
99
### Test Runners
100
101
Platform-specific implementations for executing ZIO tests within SBT.
102
103
#### JVM Test Runner
104
105
```scala { .api }
106
final class ZTestRunner(
107
val args: Array[String],
108
val remoteArgs: Array[String],
109
testClassLoader: ClassLoader
110
) extends sbt.testing.Runner {
111
val summaries: java.util.concurrent.atomic.AtomicReference[Vector[zio.test.Summary]]
112
val sendSummary: SendSummary
113
114
def tasks(defs: Array[sbt.testing.TaskDef]): Array[sbt.testing.Task]
115
def done(): String
116
}
117
```
118
119
#### JavaScript/Native Test Runners
120
121
```scala { .api }
122
abstract class ZTestRunner(
123
args: Array[String],
124
remoteArgs: Array[String],
125
testClassLoader: ClassLoader,
126
runnerType: String
127
) extends sbt.testing.Runner {
128
def sendSummary: SendSummary
129
def tasks(defs: Array[sbt.testing.TaskDef]): Array[sbt.testing.Task]
130
def done(): String
131
def receiveMessage(summary: String): Option[String]
132
def serializeTask(task: sbt.testing.Task, serializer: sbt.testing.TaskDef => String): String
133
def deserializeTask(task: String, deserializer: String => sbt.testing.TaskDef): sbt.testing.Task
134
}
135
136
class ZMasterTestRunner(
137
args: Array[String],
138
remoteArgs: Array[String],
139
testClassLoader: ClassLoader
140
) extends ZTestRunner
141
142
class ZSlaveTestRunner(
143
args: Array[String],
144
remoteArgs: Array[String],
145
testClassLoader: ClassLoader,
146
sendSummary: SendSummary
147
) extends ZTestRunner
148
```
149
150
### Test Tasks
151
152
Base class for executing individual ZIO test specifications.
153
154
```scala { .api }
155
abstract class BaseTestTask(
156
taskDef0: sbt.testing.TaskDef,
157
testClassLoader: ClassLoader,
158
sendSummary: SendSummary,
159
args: zio.test.TestArgs
160
) extends sbt.testing.Task {
161
val testClassLoader: ClassLoader
162
val sendSummary: SendSummary
163
val args: zio.test.TestArgs
164
165
final def taskDef(): sbt.testing.TaskDef
166
def execute(eventHandler: sbt.testing.EventHandler, loggers: Array[sbt.testing.Logger]): Array[sbt.testing.Task]
167
def tags(): Array[String]
168
}
169
```
170
171
Platform-specific task implementations:
172
173
```scala { .api }
174
// JVM Task
175
class ZTestTask(
176
taskDef: sbt.testing.TaskDef,
177
testClassLoader: ClassLoader,
178
sendSummary: SendSummary,
179
testArgs: zio.test.TestArgs
180
) extends BaseTestTask
181
182
// JS/Native Task (with async execution)
183
class ZTestTask(
184
taskDef: sbt.testing.TaskDef,
185
testClassLoader: ClassLoader,
186
runnerType: String,
187
sendSummary: SendSummary,
188
testArgs: zio.test.TestArgs
189
) extends BaseTestTask {
190
def execute(
191
eventHandler: sbt.testing.EventHandler,
192
loggers: Array[sbt.testing.Logger],
193
continuation: Array[sbt.testing.Task] => Unit
194
): Unit
195
}
196
```
197
198
### Test Events
199
200
SBT-compatible events generated from ZIO test execution results.
201
202
```scala { .api }
203
// JVM/JS Implementation
204
case class ZTestEvent(
205
fullyQualifiedName: String,
206
selector: sbt.testing.Selector,
207
status: sbt.testing.Status,
208
maybeThrowable: Option[Throwable],
209
duration: Long,
210
fingerprint: sbt.testing.Fingerprint
211
) extends sbt.testing.Event {
212
def throwable(): sbt.testing.OptionalThrowable
213
}
214
215
// Native Implementation (with explicit overrides)
216
case class ZTestEvent(
217
fullyQualifiedName0: String,
218
selector0: sbt.testing.Selector,
219
status0: sbt.testing.Status,
220
maybeThrowable: Option[Throwable],
221
duration0: Long,
222
fingerprint0: sbt.testing.Fingerprint
223
) extends sbt.testing.Event {
224
override def fullyQualifiedName(): String
225
override def selector(): sbt.testing.Selector
226
override def status(): sbt.testing.Status
227
override def duration(): Long
228
override def fingerprint(): sbt.testing.Fingerprint
229
def throwable(): sbt.testing.OptionalThrowable
230
}
231
232
object ZTestEvent {
233
def from[E](
234
executedSpec: zio.test.ExecutedSpec[E],
235
fullyQualifiedName: String,
236
fingerprint: sbt.testing.Fingerprint
237
): Seq[ZTestEvent]
238
}
239
```
240
241
### Task Policies
242
243
Customizable policies for merging and organizing test tasks.
244
245
```scala { .api }
246
abstract class ZTestTaskPolicy {
247
def merge(zioTasks: Array[ZTestTask]): Array[sbt.testing.Task]
248
}
249
250
class ZTestTaskPolicyDefaultImpl extends ZTestTaskPolicy {
251
override def merge(zioTasks: Array[ZTestTask]): Array[sbt.testing.Task] = zioTasks.toArray
252
}
253
```
254
255
### Summary Management
256
257
Type-safe summary handling with platform-specific serialization support.
258
259
```scala { .api }
260
type SendSummary = zio.URIO[zio.test.Summary, Unit]
261
262
object SendSummary {
263
def fromSend(send: zio.test.Summary => Unit): SendSummary
264
def fromSendM(send: zio.test.Summary => zio.UIO[Unit]): SendSummary
265
def noop: SendSummary
266
}
267
```
268
269
For JavaScript/Native distributed testing:
270
271
```scala { .api }
272
object SummaryProtocol {
273
def serialize(summary: zio.test.Summary): String
274
def deserialize(s: String): Option[zio.test.Summary]
275
def escape(token: String): String
276
def unescape(token: String): String
277
}
278
```
279
280
### Test Discovery
281
282
Fingerprint for automatic discovery of ZIO test specifications.
283
284
```scala { .api }
285
object RunnableSpecFingerprint extends sbt.testing.SubclassFingerprint {
286
def superclassName(): String
287
def isModule(): Boolean
288
def requireNoArgConstructor(): Boolean
289
}
290
```
291
292
## Types
293
294
### Core Types
295
296
```scala { .api }
297
// Re-exported from zio.test
298
type Summary = zio.test.Summary
299
type TestArgs = zio.test.TestArgs
300
type ExecutedSpec[E] = zio.test.ExecutedSpec[E]
301
type AbstractRunnableSpec = zio.test.AbstractRunnableSpec
302
303
// SBT Testing API types (from sbt.testing._)
304
type Framework = sbt.testing.Framework
305
type Runner = sbt.testing.Runner
306
type Task = sbt.testing.Task
307
type TaskDef = sbt.testing.TaskDef
308
type Event = sbt.testing.Event
309
type EventHandler = sbt.testing.EventHandler
310
type Logger = sbt.testing.Logger
311
type Fingerprint = sbt.testing.Fingerprint
312
type SubclassFingerprint = sbt.testing.SubclassFingerprint
313
type Selector = sbt.testing.Selector
314
type TestSelector = sbt.testing.TestSelector
315
type Status = sbt.testing.Status
316
type OptionalThrowable = sbt.testing.OptionalThrowable
317
```
318
319
## Platform-Specific Differences
320
321
### JVM Platform
322
- Synchronous test execution
323
- Single `ZTestRunner` implementation
324
- Direct task execution without continuations
325
326
### JavaScript Platform
327
- Master/slave runner architecture for distributed testing
328
- Asynchronous task execution with continuations
329
- Message-based summary communication via `SummaryProtocol`
330
- Task serialization/deserialization support
331
332
### Native Platform
333
- Similar to JavaScript platform architecture
334
- Supports distributed testing capabilities
335
- Platform-specific `ZTestEvent` implementation with explicit method overrides
336
337
## Error Handling
338
339
Test failures are converted to appropriate SBT events:
340
- `TestFailure.Assertion` becomes `AssertionError`
341
- `TestFailure.Runtime` becomes `RuntimeException`
342
- All errors include rendered test output with ANSI codes stripped
343
344
## Integration Notes
345
346
- Tests are automatically discovered if they extend `AbstractRunnableSpec`
347
- Test arguments can be passed through SBT's `testOptions`
348
- Summary information is collected and displayed at completion
349
- Supports SBT's parallel test execution
350
- Compatible with SBT's test filtering and selection