or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

assertions.mdcore-testing.mdindex.mdproperty-testing.mdsmart-assertions.mdtest-aspects.mdtest-services.md

test-aspects.mddocs/

0

# Test Aspects

1

2

Cross-cutting concerns for configuring test execution, lifecycle, timeouts, retries, and environment management. Test aspects provide a powerful way to modify test behavior without changing test logic.

3

4

## Capabilities

5

6

### Core Test Aspect Type

7

8

The fundamental test aspect type for transforming test specifications.

9

10

```scala { .api }

11

/**

12

* Base class for test aspects that transform test specifications

13

* @tparam R0 - Input environment requirement

14

* @tparam R1 - Output environment requirement

15

* @tparam E0 - Input error type

16

* @tparam E1 - Output error type

17

*/

18

abstract class TestAspect[-R0, +R1, -E0, +E1] {

19

/** Apply this aspect to a test specification */

20

def apply[R <: R0, E >: E0](spec: Spec[R, E]): Spec[R1, E1]

21

22

/** Compose this aspect with another aspect */

23

def >>>[R2 >: R1, R3, E2 >: E1, E3](that: TestAspect[R2, R3, E2, E3]): TestAspect[R0, R3, E0, E3]

24

25

/** Compose another aspect with this aspect */

26

def <<<[R2, E2](that: TestAspect[R2, R0, E2, E0]): TestAspect[R2, R1, E2, E1]

27

28

/** Combine aspects with logical AND */

29

def &&[R2 <: R0, R3 >: R1, E2 >: E0, E3 >: E1](that: TestAspect[R2, R3, E2, E3]): TestAspect[R2, R3, E2, E3]

30

}

31

32

/**

33

* Type aliases for common aspect patterns

34

*/

35

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

36

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

37

```

38

39

### Basic Test Aspects

40

41

Essential aspects for common test scenarios.

42

43

```scala { .api }

44

/**

45

* Identity aspect that does nothing

46

*/

47

def identity: TestAspectPoly

48

49

/**

50

* Ignore all tests (mark as ignored)

51

*/

52

def ignore: TestAspectPoly

53

54

/**

55

* Retry flaky tests up to n times until they pass

56

* @param n - Maximum number of retries

57

*/

58

def flaky(n: Int): TestAspectPoly

59

60

/**

61

* Mark tests as non-flaky (disable retries)

62

* @param n - Number of times to mark as non-flaky

63

*/

64

def nonFlaky(n: Int): TestAspectPoly

65

66

/**

67

* Repeat tests n times

68

* @param n - Number of repetitions

69

*/

70

def repeats(n: Int): TestAspectPoly

71

72

/**

73

* Retry failed tests up to n times

74

* @param n - Maximum number of retries

75

*/

76

def retries(n: Int): TestAspectPoly

77

```

78

79

**Usage Examples:**

80

81

```scala

82

import zio.test._

83

import zio.test.TestAspect._

84

85

// Apply aspects using @@ syntax

86

test("flaky test") {

87

// Test that might fail occasionally

88

assertTrue(scala.util.Random.nextBoolean())

89

} @@ flaky(3)

90

91

test("repeated test") {

92

// Test that should run multiple times

93

assertTrue(1 + 1 == 2)

94

} @@ repeats(5)

95

96

// Ignore specific tests

97

test("work in progress") {

98

assertTrue(false) // This won't run

99

} @@ ignore

100

```

101

102

### Timeout Aspects

103

104

Aspects for controlling test execution time limits.

105

106

```scala { .api }

107

/**

108

* Set timeout for test execution

109

* @param duration - Maximum execution time

110

*/

111

def timeout(duration: Duration): TestAspectPoly

112

113

/**

114

* Set timeout with warning before timeout

115

* @param duration - Maximum execution time

116

*/

117

def timeoutWarning(duration: Duration): TestAspectPoly

118

119

/**

120

* Detect non-terminating tests

121

* @param duration - Time after which to consider test non-terminating

122

*/

123

def nonTermination(duration: Duration): TestAspectPoly

124

```

125

126

**Usage Examples:**

127

128

```scala

129

import zio.test._

130

import zio.test.TestAspect._

131

132

test("long running operation") {

133

ZIO.sleep(30.seconds)

134

} @@ timeout(1.minute)

135

136

test("operation with warning") {

137

ZIO.sleep(45.seconds)

138

} @@ timeoutWarning(1.minute)

139

140

suite("time-sensitive tests")(

141

test("test 1") { assertTrue(true) },

142

test("test 2") { assertTrue(true) }

143

) @@ timeout(30.seconds) // Apply to entire suite

144

```

145

146

### Execution Strategy Aspects

147

148

Aspects controlling parallel vs sequential execution.

149

150

```scala { .api }

151

/**

152

* Execute tests sequentially

153

*/

154

def sequential: TestAspectPoly

155

156

/**

157

* Execute tests in parallel

158

*/

159

def parallel: TestAspectPoly

160

161

/**

162

* Execute tests in parallel with specific number of threads

163

* @param n - Number of parallel threads

164

*/

165

def parallelN(n: Int): TestAspectPoly

166

167

/**

168

* Use custom execution strategy

169

* @param strategy - Execution strategy to use

170

*/

171

def executionStrategy(strategy: ExecutionStrategy): TestAspectPoly

172

```

173

174

**Usage Examples:**

175

176

```scala

177

import zio.test._

178

import zio.test.TestAspect._

179

180

// Run entire suite in parallel

181

suite("parallel tests")(

182

test("test 1") { ZIO.sleep(1.second) *> assertTrue(true) },

183

test("test 2") { ZIO.sleep(1.second) *> assertTrue(true) },

184

test("test 3") { ZIO.sleep(1.second) *> assertTrue(true) }

185

) @@ parallel

186

187

// Force sequential execution for specific suite

188

suite("sequential tests")(

189

test("setup") { setupTest() },

190

test("main") { mainTest() },

191

test("cleanup") { cleanupTest() }

192

) @@ sequential

193

194

// Limit parallelism

195

suite("limited parallel")(

196

// Many tests...

197

) @@ parallelN(4)

198

```

199

200

### Lifecycle Aspects

201

202

Aspects for managing test setup and teardown.

203

204

```scala { .api }

205

/**

206

* Run effect before each test

207

* @param zio - Effect to run before each test

208

*/

209

def before[R](zio: ZIO[R, Nothing, Any]): TestAspect[Nothing, R, Nothing, Any]

210

211

/**

212

* Run effect after each test

213

* @param zio - Effect to run after each test

214

*/

215

def after[R](zio: ZIO[R, Nothing, Any]): TestAspect[Nothing, R, Nothing, Any]

216

217

/**

218

* Run effects before and after each test

219

* @param before - Effect to run before each test

220

* @param after - Effect to run after each test

221

*/

222

def around[R](before: ZIO[R, Nothing, Any], after: ZIO[R, Nothing, Any]): TestAspect[Nothing, R, Nothing, Any]

223

224

/**

225

* Run effect before all tests in a suite

226

* @param zio - Effect to run before all tests

227

*/

228

def beforeAll[R](zio: ZIO[R, Nothing, Any]): TestAspect[Nothing, R, Nothing, Any]

229

230

/**

231

* Run effect after all tests in a suite

232

* @param zio - Effect to run after all tests

233

*/

234

def afterAll[R](zio: ZIO[R, Nothing, Any]): TestAspect[Nothing, R, Nothing, Any]

235

236

/**

237

* Run effects before and after all tests in a suite

238

* @param before - Effect to run before all tests

239

* @param after - Effect to run after all tests

240

*/

241

def aroundAll[R](before: ZIO[R, Nothing, Any], after: ZIO[R, Nothing, Any]): TestAspect[Nothing, R, Nothing, Any]

242

243

/**

244

* Run effect after successful test

245

* @param zio - Effect to run after test success

246

*/

247

def afterSuccess[R](zio: ZIO[R, Nothing, Any]): TestAspect[Nothing, R, Nothing, Any]

248

249

/**

250

* Run effect after failed test

251

* @param zio - Effect to run after test failure

252

*/

253

def afterFailure[R](zio: ZIO[R, Nothing, Any]): TestAspect[Nothing, R, Nothing, Any]

254

255

/**

256

* Run effect after all tests succeed

257

* @param zio - Effect to run after all tests succeed

258

*/

259

def afterAllSuccess[R](zio: ZIO[R, Nothing, Any]): TestAspect[Nothing, R, Nothing, Any]

260

261

/**

262

* Run effect after any test fails

263

* @param zio - Effect to run after any test fails

264

*/

265

def afterAllFailure[R](zio: ZIO[R, Nothing, Any]): TestAspect[Nothing, R, Nothing, Any]

266

```

267

268

**Usage Examples:**

269

270

```scala

271

import zio.test._

272

import zio.test.TestAspect._

273

274

// Database test with setup/teardown

275

suite("database tests")(

276

test("create user") { createUserTest() },

277

test("read user") { readUserTest() },

278

test("update user") { updateUserTest() },

279

test("delete user") { deleteUserTest() }

280

) @@ beforeAll(initializeDatabase()) @@ afterAll(cleanupDatabase())

281

282

// Individual test setup

283

test("file processing") {

284

processFile("test.txt")

285

} @@ before(createTestFile()) @@ after(deleteTestFile())

286

287

// Conditional cleanup

288

test("resource test") {

289

useResource()

290

} @@ afterSuccess(logSuccess()) @@ afterFailure(logFailure())

291

```

292

293

### Environment Aspects

294

295

Aspects for providing dependencies and environment to tests.

296

297

```scala { .api }

298

/**

299

* Provide layer to tests

300

* @param layer - ZLayer to provide

301

*/

302

def fromLayer[R](layer: ZLayer[Any, Nothing, R]): TestAspect[Nothing, R, Nothing, Any]

303

304

/**

305

* Provide shared layer to tests (layer is created once and reused)

306

* @param layer - ZLayer to provide and share

307

*/

308

def fromLayerShared[R](layer: ZLayer[Any, Nothing, R]): TestAspect[Nothing, R, Nothing, Any]

309

310

/**

311

* Use custom config provider

312

* @param provider - ConfigProvider to use

313

*/

314

def withConfigProvider(provider: ConfigProvider): TestAspectPoly

315

```

316

317

**Usage Examples:**

318

319

```scala

320

import zio.test._

321

import zio.test.TestAspect._

322

323

// Provide database layer to tests

324

suite("service tests")(

325

test("user service") {

326

for {

327

service <- ZIO.service[UserService]

328

user <- service.createUser("Alice")

329

} yield assertTrue(user.name == "Alice")

330

}

331

) @@ fromLayer(DatabaseLayer.test ++ UserService.live)

332

333

// Shared expensive resource

334

suite("integration tests")(

335

// Multiple tests using shared database connection

336

) @@ fromLayerShared(DatabaseConnectionPool.live)

337

338

// Custom configuration

339

suite("config tests")(

340

test("load config") {

341

for {

342

config <- ZIO.config[AppConfig]

343

} yield assertTrue(config.appName.nonEmpty)

344

}

345

) @@ withConfigProvider(ConfigProvider.fromMap(Map("appName" -> "TestApp")))

346

```

347

348

### Property Testing Configuration

349

350

Aspects for configuring property-based test parameters.

351

352

```scala { .api }

353

/**

354

* Set number of samples for property tests

355

* @param n - Number of samples to generate

356

*/

357

def samples(n: Int): TestAspectPoly

358

359

/**

360

* Set number of shrinking attempts

361

* @param n - Maximum shrinking iterations

362

*/

363

def shrinks(n: Int): TestAspectPoly

364

365

/**

366

* Set generator size parameter

367

* @param n - Size parameter for generators

368

*/

369

def size(n: Int): TestAspectPoly

370

371

/**

372

* Set generator size using function

373

* @param f - Function to transform size parameter

374

*/

375

def sized(f: Int => Int): TestAspectPoly

376

377

/**

378

* Set random seed for reproducible tests

379

* @param seed - Random seed value

380

*/

381

def setSeed(seed: Long): TestAspectPoly

382

```

383

384

**Usage Examples:**

385

386

```scala

387

import zio.test._

388

import zio.test.TestAspect._

389

390

test("property test with more samples") {

391

check(Gen.int) { n =>

392

assertTrue((n + 1) > n)

393

}

394

} @@ samples(10000)

395

396

test("property test with larger values") {

397

check(Gen.listOf(Gen.int)) { numbers =>

398

assertTrue(numbers.reverse.reverse == numbers)

399

}

400

} @@ size(1000)

401

402

test("reproducible property test") {

403

check(Gen.int) { n =>

404

assertTrue(n.isInstanceOf[Int])

405

}

406

} @@ setSeed(42L)

407

```

408

409

### Platform and Conditional Aspects

410

411

Aspects for conditional test execution based on platform or environment.

412

413

```scala { .api }

414

/**

415

* Run only if environment variable matches condition

416

* @param name - Environment variable name

417

* @param predicate - Condition to check variable value

418

*/

419

def ifEnv(name: String, predicate: String => Boolean): TestAspectPoly

420

421

/**

422

* Run only if environment variable is set

423

* @param name - Environment variable name

424

*/

425

def ifEnvSet(name: String): TestAspectPoly

426

427

/**

428

* Run only if environment variable is not set

429

* @param name - Environment variable name

430

*/

431

def ifEnvNotSet(name: String): TestAspectPoly

432

433

/**

434

* Run conditionally based on environment variable option

435

* @param name - Environment variable name

436

* @param predicate - Condition to check optional value

437

*/

438

def ifEnvOption(name: String, predicate: Option[String] => Boolean): TestAspectPoly

439

440

/**

441

* Run only if system property matches condition

442

* @param name - System property name

443

* @param predicate - Condition to check property value

444

*/

445

def ifProp(name: String, predicate: String => Boolean): TestAspectPoly

446

447

/**

448

* Run only if system property is set

449

* @param name - System property name

450

*/

451

def ifPropSet(name: String): TestAspectPoly

452

453

/**

454

* Run only if system property is not set

455

* @param name - System property name

456

*/

457

def ifPropNotSet(name: String): TestAspectPoly

458

459

/**

460

* Run conditionally based on system property option

461

* @param name - System property name

462

* @param predicate - Condition to check optional value

463

*/

464

def ifPropOption(name: String, predicate: Option[String] => Boolean): TestAspectPoly

465

466

/**

467

* Run only on JVM platform

468

*/

469

def jvmOnly: TestAspectPoly

470

471

/**

472

* Run only on JavaScript platform

473

*/

474

def jsOnly: TestAspectPoly

475

476

/**

477

* Run only on Scala Native platform

478

*/

479

def nativeOnly: TestAspectPoly

480

481

/**

482

* Run only on Unix systems

483

*/

484

def unix: TestAspectPoly

485

486

/**

487

* Run only on Windows systems

488

*/

489

def windows: TestAspectPoly

490

491

/**

492

* Run conditionally based on operating system

493

* @param predicate - Condition to check OS name

494

*/

495

def os(predicate: String => Boolean): TestAspectPoly

496

497

/**

498

* Run only on Scala 2

499

*/

500

def scala2Only: TestAspectPoly

501

502

/**

503

* Run only on Scala 3

504

*/

505

def scala3Only: TestAspectPoly

506

```

507

508

**Usage Examples:**

509

510

```scala

511

import zio.test._

512

import zio.test.TestAspect._

513

514

// Platform-specific tests

515

test("JVM-specific functionality") {

516

// JVM-only code

517

assertTrue(System.getProperty("java.version").nonEmpty)

518

} @@ jvmOnly

519

520

test("Unix file permissions") {

521

// Unix-specific test

522

assertTrue(java.io.File.separatorChar == '/')

523

} @@ unix

524

525

// Environment-conditional tests

526

test("production database test") {

527

// Only run if ENVIRONMENT=production

528

connectToDatabase()

529

} @@ ifEnv("ENVIRONMENT", _ == "production")

530

531

test("CI-only test") {

532

// Only run in CI environment

533

runExpensiveTest()

534

} @@ ifEnvSet("CI")

535

536

// Scala version specific

537

test("Scala 3 feature") {

538

// Test Scala 3 specific features

539

assertTrue(true)

540

} @@ scala3Only

541

```

542

543

### State Management Aspects

544

545

Aspects for saving and restoring test service state.

546

547

```scala { .api }

548

/**

549

* Restore using custom restorable

550

* @param restorable - Custom restorable implementation

551

*/

552

def restore[R](restorable: Restorable[R]): TestAspect[Nothing, R, Nothing, Any]

553

554

/**

555

* Restore test clock state after each test

556

*/

557

def restoreTestClock: TestAspectPoly

558

559

/**

560

* Restore test console state after each test

561

*/

562

def restoreTestConsole: TestAspectPoly

563

564

/**

565

* Restore test random state after each test

566

*/

567

def restoreTestRandom: TestAspectPoly

568

569

/**

570

* Restore test system state after each test

571

*/

572

def restoreTestSystem: TestAspectPoly

573

574

/**

575

* Restore entire test environment state after each test

576

*/

577

def restoreTestEnvironment: TestAspectPoly

578

```

579

580

**Usage Examples:**

581

582

```scala

583

import zio.test._

584

import zio.test.TestAspect._

585

586

suite("clock tests")(

587

test("advance time") {

588

TestClock.adjust(1.hour) *>

589

assertTrue(true)

590

},

591

test("time is reset") {

592

// Clock state restored from previous test

593

for {

594

time <- Clock.instant

595

} yield assertTrue(time.getEpochSecond == 0)

596

}

597

) @@ restoreTestClock

598

599

suite("console tests")(

600

test("write output") {

601

Console.printLine("test output") *>

602

assertTrue(true)

603

},

604

test("output is cleared") {

605

// Console state restored from previous test

606

for {

607

output <- TestConsole.output

608

} yield assertTrue(output.isEmpty)

609

}

610

) @@ restoreTestConsole

611

```

612

613

### Diagnostic and Analysis Aspects

614

615

Aspects for debugging and analyzing test execution.

616

617

```scala { .api }

618

/**

619

* Add diagnostic information to test execution

620

* @param duration - Duration to wait before showing diagnostics

621

*/

622

def diagnose(duration: Duration): TestAspectPoly

623

624

/**

625

* Suppress test output (run silently)

626

*/

627

def silent: TestAspectPoly

628

629

/**

630

* Add tags to tests for filtering and organization

631

* @param tag - Primary tag

632

* @param tags - Additional tags

633

*/

634

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

635

```

636

637

### Verification Aspects

638

639

Aspects for adding verification conditions to tests.

640

641

```scala { .api }

642

/**

643

* Add verification condition to test results

644

* @param assertion - Assertion to verify against test result

645

*/

646

def verify(assertion: Assertion[TestResult]): TestAspectPoly

647

648

/**

649

* Expect test to fail with specific condition

650

* @param assertion - Assertion to verify against test failure

651

*/

652

def failing[E](assertion: Assertion[TestFailure[E]]): TestAspect[Nothing, Any, E, Nothing]

653

```

654

655

**Usage Examples:**

656

657

```scala

658

import zio.test._

659

import zio.test.TestAspect._

660

661

test("expected failure") {

662

// This test is expected to fail

663

assertTrue(false)

664

} @@ failing(anything)

665

666

test("performance verification") {

667

expensiveOperation()

668

} @@ verify(anything) @@ diagnose(5.seconds)

669

670

// Tagged tests for organization

671

suite("integration tests")(

672

test("database test") { dbTest() } @@ tag("db", "integration"),

673

test("api test") { apiTest() } @@ tag("api", "integration"),

674

test("auth test") { authTest() } @@ tag("auth", "integration")

675

)

676

```

677

678

### Aspect Composition

679

680

Methods for combining and composing aspects.

681

682

```scala { .api }

683

// Combine aspects using && operator

684

val combinedAspect = timeout(30.seconds) && parallel && samples(1000)

685

686

// Chain aspects using >>> operator

687

val chainedAspect = beforeAll(setup()) >>> timeout(1.minute) >>> afterAll(cleanup())

688

689

// Apply multiple aspects to test

690

test("complex test") {

691

complexOperation()

692

} @@ timeout(1.minute) @@ flaky(3) @@ restoreTestClock @@ tag("slow", "integration")

693

```

694

695

**Usage Examples:**

696

697

```scala

698

import zio.test._

699

import zio.test.TestAspect._

700

701

// Complex aspect composition

702

val integrationTestAspect =

703

beforeAll(setupIntegrationEnvironment()) @@

704

afterAll(cleanupIntegrationEnvironment()) @@

705

timeout(5.minutes) @@

706

flaky(2) @@

707

tag("integration") @@

708

ifEnvSet("RUN_INTEGRATION_TESTS")

709

710

suite("integration tests")(

711

test("end-to-end workflow") { e2eTest() },

712

test("external service integration") { externalServiceTest() }

713

) @@ integrationTestAspect

714

```