ZIO Test is a zero-dependency testing library that makes it easy to test effectual programs
npx @tessl/cli install tessl/maven-dev-zio--zio-test@2.1.00
# ZIO Test
1
2
ZIO Test is a comprehensive testing framework for effectual Scala programs built with ZIO. It provides zero-dependency testing with advanced features including property-based testing, sophisticated assertions, test aspects for cross-cutting concerns, and deterministic test services for reliable testing of concurrent and asynchronous code.
3
4
## Package Information
5
6
- **Package Name**: zio-test
7
- **Package Type**: maven
8
- **Language**: Scala
9
- **Installation**: `libraryDependencies += "dev.zio" %% "zio-test" % "2.1.19"`
10
- **Test Integration**: `libraryDependencies += "dev.zio" %% "zio-test-sbt" % "2.1.19" % Test`
11
12
## Core Imports
13
14
```scala
15
import zio.test._
16
import zio.test.Assertion._
17
import zio.test.Gen._
18
```
19
20
For specific functionality:
21
22
```scala
23
// Property-based testing
24
import zio.test.{Gen, check, checkAll}
25
26
// Test aspects
27
import zio.test.TestAspect.{timeout, parallel, eventually}
28
29
// Test services
30
import zio.test.{TestClock, TestConsole, TestRandom, TestSystem}
31
32
// Advanced features
33
import zio.test.laws._ // Laws-based property testing
34
import zio.test.diff._ // Value differencing system
35
import zio.test.render._ // Test result rendering
36
import zio.test.poly._ // Polymorphic generators
37
```
38
39
## Basic Usage
40
41
```scala
42
import zio.test._
43
import zio.test.Assertion._
44
45
object BasicExampleSpec extends ZIOSpecDefault {
46
def spec = suite("Basic Examples")(
47
test("simple assertion") {
48
val result = 2 + 2
49
assertTrue(result == 4)
50
},
51
52
test("ZIO effect testing") {
53
for {
54
time <- zio.Clock.currentTime(java.util.concurrent.TimeUnit.MILLISECONDS)
55
} yield assertTrue(time > 0L)
56
},
57
58
test("property-based testing") {
59
check(Gen.int) { n =>
60
assertTrue((n + n) == (n * 2))
61
}
62
}
63
)
64
}
65
```
66
67
## Architecture
68
69
ZIO Test is built around several key components:
70
71
- **Test Definition DSL**: `test`, `suite`, `ZTest` for creating test specifications
72
- **Assertion System**: Rich set of combinable assertions with detailed failure reporting
73
- **Property-Based Testing**: Comprehensive generator system with automatic shrinking
74
- **Test Aspects**: Cross-cutting concerns like timeouts, retries, parallelism, and platform-specific execution
75
- **Deterministic Services**: `TestClock`, `TestConsole`, `TestRandom`, `TestSystem` for predictable testing
76
- **Test Environment**: Layered dependency injection system for test services and configuration
77
- **Execution Engine**: Parallel and sequential test execution with comprehensive reporting
78
79
## Capabilities
80
81
### Test Definition and Structure
82
83
Core DSL for creating tests and test suites with support for nested suites, test organization, and ZIO effect integration.
84
85
```scala { .api }
86
def test[R](label: String)(assertion: => ZIO[R, Any, TestResult]): Spec[R, Any]
87
def suite[R](label: String)(specs: Spec[R, Any]*): Spec[R, Any]
88
89
trait Spec[+R, +E] {
90
def @@[R1 <: R](aspect: TestAspect[Nothing, R1, Nothing, Any]): Spec[R1, E]
91
}
92
93
type ZTest[-R, +E] = ZIO[R, TestFailure[E], TestSuccess]
94
95
// Base classes for test specifications
96
abstract class ZIOSpec[R] {
97
def spec: Spec[R, Any]
98
}
99
100
abstract class ZIOSpecDefault extends ZIOSpec[TestEnvironment] {
101
def spec: Spec[TestEnvironment, Any]
102
}
103
104
abstract class ZIOSpecAbstract[R](implicit trace: Trace) extends ZIOSpec[R] {
105
def spec: Spec[R, Any]
106
}
107
```
108
109
[Test Definition and Structure](./test-definition.md)
110
111
### Assertions and Test Results
112
113
Comprehensive assertion library with combinable assertions, smart error messages, and detailed failure reporting.
114
115
```scala { .api }
116
def assertTrue(exprs: Boolean*): TestResult
117
def assert[A](expr: => A)(assertion: Assertion[A]): TestResult
118
def assertZIO[R, E, A](effect: ZIO[R, E, A])(assertion: Assertion[A]): ZIO[R, E, TestResult]
119
120
trait Assertion[-A] {
121
def apply(value: A): TestResult
122
def &&(that: Assertion[A]): Assertion[A]
123
def ||(that: Assertion[A]): Assertion[A]
124
def unary_! : Assertion[A]
125
}
126
127
// Core assertion functions
128
def equalTo[A](expected: A): Assertion[A]
129
def isTrue: Assertion[Boolean]
130
def contains[A](element: A): Assertion[Iterable[A]]
131
def hasSize[A](assertion: Assertion[Int]): Assertion[Iterable[A]]
132
```
133
134
[Assertions and Test Results](./assertions.md)
135
136
### Property-Based Testing
137
138
Advanced property-based testing with sophisticated generators, automatic shrinking, and configurable test execution.
139
140
```scala { .api }
141
def check[R <: ZAny, A](rv: Gen[R, A])(test: A => TestResult): ZIO[R with TestConfig, Nothing, TestResult]
142
def checkAll[R <: ZAny, A](rv: Gen[R, A])(test: A => TestResult): ZIO[R with TestConfig, Nothing, TestResult]
143
144
trait Gen[+R, +A] {
145
def map[B](f: A => B): Gen[R, B]
146
def flatMap[R1 <: R, B](f: A => Gen[R1, B]): Gen[R1, B]
147
def filter(f: A => Boolean): Gen[R, A]
148
def sample: ZStream[R, Nothing, Sample[R, A]]
149
}
150
151
// Generator constructors
152
val anyInt: Gen[Any, Int]
153
val anyString: Gen[Any, String]
154
def listOfN[R, A](n: Int)(g: Gen[R, A]): Gen[R, List[A]]
155
def oneOf[R, A](first: Gen[R, A], rest: Gen[R, A]*): Gen[R, A]
156
```
157
158
[Property-Based Testing](./property-testing.md)
159
160
### Test Aspects
161
162
Cross-cutting concerns for test execution including timeouts, retries, parallelism, and platform-specific behavior.
163
164
```scala { .api }
165
trait TestAspect[-LowerR, +UpperR, -LowerE, +UpperE] {
166
def apply[R >: LowerR <: UpperR, E >: LowerE <: UpperE](
167
spec: Spec[R, E]
168
): Spec[R, E]
169
}
170
171
// Common test aspects
172
object TestAspect {
173
def timeout(duration: Duration): TestAspectAtLeastR[Live]
174
val parallel: TestAspectPoly
175
val sequential: TestAspectPoly
176
val eventually: TestAspectAtLeastR[Live]
177
val flaky: TestAspectPoly
178
val ignore: TestAspectPoly
179
val js: TestAspectPoly
180
val jvm: TestAspectPoly
181
}
182
```
183
184
[Test Aspects](./test-aspects.md)
185
186
### Test Services
187
188
Deterministic test services that replace system services during testing for predictable, reproducible test execution.
189
190
```scala { .api }
191
trait TestClock extends Clock {
192
def adjust(duration: Duration): UIO[Unit]
193
def setTime(duration: Duration): UIO[Unit]
194
def timeZone: UIO[ZoneId]
195
}
196
197
trait TestConsole extends Console {
198
def output: UIO[Vector[String]]
199
def clearOutput: UIO[Unit]
200
def feedLines(lines: String*): UIO[Unit]
201
}
202
203
trait TestRandom extends Random {
204
def setSeed(seed: Long): UIO[Unit]
205
def feedBooleans(booleans: Boolean*): UIO[Unit]
206
def clearBooleans: UIO[Unit]
207
}
208
209
trait TestSystem extends System {
210
def putEnv(name: String, value: String): UIO[Unit]
211
def putProperty(name: String, value: String): UIO[Unit]
212
}
213
```
214
215
[Test Services](./test-services.md)
216
217
### Test Configuration and Environment
218
219
Configuration system for controlling test execution parameters and environment setup for dependency injection.
220
221
```scala { .api }
222
trait TestConfig {
223
def repeats: Int
224
def retries: Int
225
def samples: Int
226
def shrinks: Int
227
}
228
229
type TestEnvironment = Annotations with Live with Sized with TestConfig
230
231
object TestEnvironment {
232
val live: ZLayer[Clock with Console with System with Random, Nothing, TestEnvironment]
233
}
234
235
val testEnvironment: ZLayer[Any, Nothing, TestEnvironment]
236
```
237
238
[Configuration and Environment](./configuration.md)
239
240
### Laws-Based Property Testing
241
242
Advanced property-based testing using mathematical laws and algebraic properties for typeclass verification.
243
244
```scala { .api }
245
trait Laws[Caps, R] {
246
def laws: List[ZLaws[Caps, R]]
247
}
248
249
trait ZLaws[-Caps, -R] {
250
def run[R1 <: R, A](implicit
251
checkConstructor: CheckConstructor[R1],
252
caps: Caps,
253
gen: GenF[R1, A]
254
): URIO[R1, TestResult]
255
}
256
257
object Laws {
258
def derive[F[_], Caps, R](implicit
259
laws: Laws[Caps, R]
260
): ZLaws[Caps, R]
261
}
262
```
263
264
### Value Differencing System
265
266
System for computing and rendering differences between values for enhanced test failure reporting.
267
268
```scala { .api }
269
trait Diff[A] {
270
def apply(x: A, y: A): DiffResult
271
}
272
273
sealed trait DiffResult {
274
def render: String
275
def isIdentical: Boolean
276
}
277
278
object Diff {
279
val string: Diff[String]
280
val boolean: Diff[Boolean]
281
val int: Diff[Int]
282
def option[A](implicit diff: Diff[A]): Diff[Option[A]]
283
def either[A, B](implicit diffA: Diff[A], diffB: Diff[B]): Diff[Either[A, B]]
284
}
285
```
286
287
### Test Execution and Reporting
288
289
System for running tests and collecting results with support for various execution strategies and event handling.
290
291
```scala { .api }
292
trait TestRunner[R, E] {
293
def run(spec: Spec[R, E]): ZIO[R, Nothing, Summary]
294
}
295
296
trait TestExecutor[R, E] {
297
def run(spec: Spec[R, E], defExec: ExecutionStrategy): ZIO[R, Nothing, ExecutionResult[E]]
298
}
299
300
object TestRunner {
301
def default[R, E]: TestRunner[R, E]
302
}
303
304
// Execution events
305
sealed trait ExecutionEvent
306
case class SuiteStarted(labels: List[String]) extends ExecutionEvent
307
case class SuiteCompleted(labels: List[String]) extends ExecutionEvent
308
case class TestStarted(labels: List[String]) extends ExecutionEvent
309
case class TestCompleted(labels: List[String], result: TestResult) extends ExecutionEvent
310
311
// Test results and summaries
312
case class Summary(
313
success: Int,
314
fail: Int,
315
ignore: Int,
316
failureDetails: String
317
) {
318
def total: Int = success + fail + ignore
319
}
320
321
sealed trait ExecutionStrategy
322
object ExecutionStrategy {
323
case object Sequential extends ExecutionStrategy
324
case object Parallel extends ExecutionStrategy
325
}
326
```
327
328
## Types
329
330
```scala { .api }
331
// Core test types
332
trait TestResult {
333
def isSuccess: Boolean
334
def isFailure: Boolean
335
def ??(message: String): TestResult
336
}
337
338
sealed trait TestFailure[+E] {
339
def &&[E1 >: E](that: TestFailure[E1]): TestFailure[E1]
340
def ||[E1 >: E](that: TestFailure[E1]): TestFailure[E1]
341
def unary_! : TestFailure[E]
342
}
343
344
case class TestSuccess() extends AnyVal
345
346
// Diff system types
347
trait Diff[A] {
348
def apply(x: A, y: A): DiffResult
349
}
350
351
sealed trait DiffResult {
352
def render: String
353
}
354
355
// Test trace for debugging
356
case class TestTrace(
357
rendered: String,
358
span: Span
359
)
360
361
// Test structure types
362
trait Spec[+R, +E]
363
case class SpecCase[+R, +E](
364
label: String,
365
test: ZIO[R, TestFailure[E], TestSuccess],
366
annotations: TestAnnotationMap
367
)
368
369
// Sample and generation types
370
trait Sample[+R, +A] {
371
def value: A
372
def shrink: ZStream[R, Nothing, Sample[R, A]]
373
}
374
375
case class Sized(size: Int) extends AnyVal
376
```