or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

assertions.mdindex.mdmocking.mdproperty-testing.mdtest-aspects.mdtest-environment.mdtest-execution.mdtest-specifications.md

test-aspects.mddocs/

0

# Test Aspects

1

2

Composable test transformations for modifying test behavior including retry, timeout, and parallel execution.

3

4

## Capabilities

5

6

### TestAspect Class

7

8

Core abstraction for transforming test behavior.

9

10

```scala { .api }

11

/**

12

* Test aspect that transforms test specifications

13

* @tparam LowerR - Minimum environment requirement

14

* @tparam UpperR - Maximum environment requirement

15

* @tparam LowerE - Minimum error type

16

* @tparam UpperE - Maximum error type

17

*/

18

abstract class TestAspect[+LowerR, -UpperR, +LowerE, -UpperE] {

19

/** Applies aspect to test specification */

20

def apply[R, E](spec: ZSpec[R, E]): ZSpec[R, E]

21

22

/** Composes with another aspect */

23

def andThen[LowerR1, UpperR1, LowerE1, UpperE1](

24

that: TestAspect[LowerR1, UpperR1, LowerE1, UpperE1]

25

): TestAspect[LowerR with LowerR1, UpperR1, LowerE with LowerE1, UpperE1]

26

27

/** Alias for andThen */

28

def >>>[LowerR1, UpperR1, LowerE1, UpperE1](

29

that: TestAspect[LowerR1, UpperR1, LowerE1, UpperE1]

30

): TestAspect[LowerR with LowerR1, UpperR1, LowerE with LowerE1, UpperE1]

31

}

32

```

33

34

### Lifecycle Aspects

35

36

Aspects that run effects before, after, or around test execution.

37

38

```scala { .api }

39

/** Runs effect before test execution */

40

def before[R](effect: ZIO[R, Nothing, Any]): TestAspectAtLeastR[R]

41

42

/** Runs effect after test execution */

43

def after[R](effect: ZIO[R, Nothing, Any]): TestAspectAtLeastR[R]

44

45

/** Runs effect after test success */

46

def afterSuccess[R](effect: ZIO[R, Nothing, Any]): TestAspectAtLeastR[R]

47

48

/** Runs effect after test failure */

49

def afterFailure[R](effect: ZIO[R, Nothing, Any]): TestAspectAtLeastR[R]

50

51

/** Runs effects before all tests in suite */

52

def beforeAll[R](effect: ZIO[R, Nothing, Any]): TestAspectAtLeastR[R]

53

54

/** Runs effects after all tests in suite */

55

def afterAll[R](effect: ZIO[R, Nothing, Any]): TestAspectAtLeastR[R]

56

57

/** Brackets test execution with setup and cleanup */

58

def around[R, A](

59

before: ZIO[R, Nothing, A]

60

)(after: A => ZIO[R, Nothing, Any]): TestAspectAtLeastR[R]

61

```

62

63

### Execution Control Aspects

64

65

Aspects that control how and when tests are executed.

66

67

```scala { .api }

68

/** Ignores test (marks as skipped) */

69

val ignore: TestAspectPoly

70

71

/** Runs test exactly once */

72

val once: TestAspectPoly

73

74

/** Runs tests in parallel */

75

val parallel: TestAspectPoly

76

77

/** Runs tests sequentially */

78

val sequential: TestAspectPoly

79

80

/** Sets test timeout */

81

def timeout(duration: Duration): TestAspectPoly

82

83

/** Warns about slow tests */

84

def diagnose(duration: Duration): TestAspectPoly

85

86

/** Warns if test takes longer than duration */

87

def timeoutWarning(duration: Duration): TestAspectPoly

88

```

89

90

### Retry and Flaky Test Aspects

91

92

Aspects for handling unreliable or flaky tests.

93

94

```scala { .api }

95

/** Marks test as flaky (may fail occasionally) */

96

val flaky: TestAspectPoly

97

98

/** Marks test as non-flaky (must always pass) */

99

val nonFlaky: TestAspectPoly

100

101

/** Retries test until success (eventually) */

102

val eventually: TestAspectPoly

103

104

/** Retries test N times on failure */

105

def retryN(n: Int): TestAspectPoly

106

107

/** Retries test according to schedule */

108

def retry[R](schedule: Schedule[R, TestFailure[Any], Any]): TestAspectAtLeastR[R]

109

110

/** Requires test to succeed (no retries) */

111

val success: TestAspectPoly

112

```

113

114

### Repetition Aspects

115

116

Aspects for running tests multiple times.

117

118

```scala { .api }

119

/** Repeats test N times */

120

def repeatN(n: Int): TestAspectPoly

121

122

/** Repeats test according to schedule */

123

def repeat[R](schedule: Schedule[R, TestResult, Any]): TestAspectAtLeastR[R]

124

```

125

126

### Configuration Aspects

127

128

Aspects that modify test environment or configuration.

129

130

```scala { .api }

131

/** Sets generator size for property tests */

132

def sized(size: Int): TestAspectPoly

133

134

/** Sets number of shrinking attempts */

135

def shrinks(n: Int): TestAspectPoly

136

137

/** Sets number of samples for property tests */

138

def samples(n: Int): TestAspectPoly

139

140

/** Adds tags to test */

141

def tag(tag: String, tags: String*): TestAspectPoly

142

143

/** Times test execution */

144

val timed: TestAspectPoly

145

```

146

147

### Platform-Specific Aspects

148

149

Aspects that control test execution on different platforms.

150

151

```scala { .api }

152

/** Runs test only on JVM */

153

val jvmOnly: TestAspectPoly

154

155

/** Runs test only on JavaScript */

156

val jsOnly: TestAspectPoly

157

158

/** Runs test only on Scala Native */

159

val nativeOnly: TestAspectPoly

160

161

/** Runs test only on specified platforms */

162

def platformSpecific[R, E, A](

163

js: => A,

164

jvm: => A

165

)(f: A => ZTest[R, E]): ZTest[R, E]

166

```

167

168

### Resource Management Aspects

169

170

Aspects for managing resources during test execution.

171

172

```scala { .api }

173

/** Restores test state after execution */

174

def restore[R](f: ZIO[R, Nothing, TestResult] => ZIO[R, Nothing, TestResult]): TestAspectAtLeastR[R]

175

176

/** Provides managed resource to test */

177

def aroundManaged[R, A](managed: Managed[Nothing, A]): TestAspectAtLeastR[R]

178

179

/** Provides layer to test */

180

def provideLayer[R0, R, E](layer: ZLayer[R0, E, R]): TestAspect[Nothing, R0, E, Any]

181

182

/** Provides custom layer to test */

183

def provideCustomLayer[R0, R, E](layer: ZLayer[R0, E, R]): TestAspect[Nothing, R0, E, Any]

184

```

185

186

## Type Aliases

187

188

```scala { .api }

189

/**

190

* Test aspect that requires at least environment R

191

*/

192

type TestAspectAtLeastR[R] = TestAspect[Nothing, R, Nothing, Any]

193

194

/**

195

* Polymorphic test aspect with no environment or error constraints

196

*/

197

type TestAspectPoly = TestAspect[Nothing, Any, Nothing, Any]

198

```

199

200

## Usage Examples

201

202

### Basic Aspect Application

203

204

```scala

205

import zio.test._

206

import zio.duration._

207

208

// Apply single aspect

209

test("flaky test") {

210

assert(scala.util.Random.nextBoolean())(isTrue)

211

} @@ TestAspect.flaky

212

213

// Apply multiple aspects

214

test("complex test") {

215

assert(2 + 2)(equalTo(4))

216

} @@ TestAspect.timeout(30.seconds) @@ TestAspect.retryN(3)

217

218

// Apply to entire suite

219

suite("Parallel Suite")(

220

test("test 1")(assert(true)(isTrue)),

221

test("test 2")(assert(true)(isTrue))

222

) @@ TestAspect.parallel

223

```

224

225

### Lifecycle Management

226

227

```scala

228

suite("Database Tests")(

229

test("insert user") {

230

// test implementation

231

assert(true)(isTrue)

232

},

233

234

test("update user") {

235

// test implementation

236

assert(true)(isTrue)

237

}

238

) @@ TestAspect.beforeAll(initializeDatabase) @@

239

TestAspect.afterAll(cleanupDatabase)

240

241

// Per-test lifecycle

242

test("isolated test") {

243

assert(true)(isTrue)

244

} @@ TestAspect.around(createTestData)(cleanupTestData)

245

```

246

247

### Retry and Flaky Tests

248

249

```scala

250

import zio.test._

251

import zio.schedule._

252

253

// Simple retry

254

test("unstable network call") {

255

// test that might fail due to network issues

256

assert(true)(isTrue)

257

} @@ TestAspect.retryN(5)

258

259

// Eventually succeeds (keeps retrying)

260

test("eventually passing") {

261

assert(scala.util.Random.nextInt(10))(isGreaterThan(8))

262

} @@ TestAspect.eventually

263

264

// Custom retry schedule

265

test("scheduled retry") {

266

assert(true)(isTrue)

267

} @@ TestAspect.retry(Schedule.exponential(100.millis) && Schedule.recurs(3))

268

269

// Mark as flaky but still run

270

test("known flaky test") {

271

assert(System.currentTimeMillis() % 2 == 0)(isTrue)

272

} @@ TestAspect.flaky

273

```

274

275

### Platform-Specific Tests

276

277

```scala

278

suite("Platform Tests")(

279

test("JVM specific feature") {

280

// test JVM-only functionality

281

assert(true)(isTrue)

282

} @@ TestAspect.jvmOnly,

283

284

test("JavaScript specific feature") {

285

// test JS-only functionality

286

assert(true)(isTrue)

287

} @@ TestAspect.jsOnly,

288

289

test("cross-platform feature") {

290

assert(2 + 2)(equalTo(4))

291

}

292

)

293

```

294

295

### Performance and Timing

296

297

```scala

298

suite("Performance Tests")(

299

test("fast operation") {

300

// should complete quickly

301

assert(true)(isTrue)

302

} @@ TestAspect.timeout(1.second),

303

304

test("operation with timing") {

305

Thread.sleep(100)

306

assert(true)(isTrue)

307

} @@ TestAspect.timed,

308

309

test("slow operation warning") {

310

Thread.sleep(50)

311

assert(true)(isTrue)

312

} @@ TestAspect.diagnose(10.millis)

313

)

314

```

315

316

### Property Testing Configuration

317

318

```scala

319

import zio.test.Gen._

320

321

test("property test configuration") {

322

check(int) { n =>

323

assert(n * 2)(equalTo(n + n))

324

}

325

} @@ TestAspect.samples(1000) @@

326

TestAspect.shrinks(100) @@

327

TestAspect.sized(50)

328

```

329

330

### Resource Management

331

332

```scala

333

val databaseLayer = ZLayer.fromManaged {

334

Managed.make(initDatabase)(_.close())

335

}

336

337

suite("Database Integration Tests")(

338

test("query users") {

339

// test using database

340

assert(true)(isTrue)

341

},

342

343

test("insert user") {

344

// test using database

345

assert(true)(isTrue)

346

}

347

) @@ TestAspect.provideCustomLayer(databaseLayer)

348

```

349

350

### Custom Aspects

351

352

```scala

353

// Custom aspect that logs test execution

354

def logged[R <: TestLogger](message: String): TestAspectAtLeastR[R] =

355

TestAspect.before(TestLogger.logLine(s"Starting: $message")) >>>

356

TestAspect.after(TestLogger.logLine(s"Finished: $message"))

357

358

// Usage

359

test("logged test") {

360

assert(true)(isTrue)

361

} @@ logged("my important test")

362

363

// Aspect composition

364

val resilientTest = TestAspect.retryN(3) >>>

365

TestAspect.timeout(10.seconds) >>>

366

TestAspect.diagnose(1.second)

367

368

test("resilient test") {

369

assert(true)(isTrue)

370

} @@ resilientTest

371

```

372

373

### Conditional Aspects

374

375

```scala

376

// Apply aspect conditionally

377

def whenCI(aspect: TestAspectPoly): TestAspectPoly =

378

if (sys.env.contains("CI")) aspect else TestAspect.identity

379

380

test("CI test") {

381

assert(true)(isTrue)

382

} @@ whenCI(TestAspect.retryN(5))

383

384

// Environment-based aspects

385

test("development test") {

386

assert(true)(isTrue)

387

} @@ TestAspect.ifEnv("ENV", "dev")(TestAspect.ignore)

388

```