or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

assertions.mdcore-dsl.mdindex.mdmock-testing.mdproperty-testing.mdspecifications.mdtest-aspects.mdtest-environment.md

specifications.mddocs/

0

# Test Specifications

1

2

Base classes and utilities for creating runnable test specifications. The specification framework provides the structure for organizing and executing tests.

3

4

## Capabilities

5

6

### Core Specification Classes

7

8

Foundation classes for creating test specifications.

9

10

```scala { .api }

11

/**

12

* Base spec class representing a test specification tree

13

* @param R - Environment required by the spec

14

* @param E - Error type the spec may produce

15

* @param T - Type of test results

16

*/

17

final case class Spec[-R, +E, +T](caseValue: SpecCase[R, E, T, Spec[R, E, T]]) {

18

/**

19

* Combine this spec with another spec

20

* @param that - Spec to combine with

21

* @returns Combined spec containing both

22

*/

23

def +[R1 <: R, E1 >: E, T1 >: T](that: Spec[R1, E1, T1]): Spec[R1, E1, T1]

24

25

/**

26

* Apply a test aspect to this spec

27

* @param aspect - Aspect to apply

28

* @returns Spec with aspect applied

29

*/

30

def @@[R0 <: R1, R1 <: R, E0, E1, E2 >: E0 <: E1](

31

aspect: TestAspect[R0, R1, E0, E1]

32

): ZSpec[R1, E2]

33

34

/**

35

* Conditionally execute this spec

36

* @param b - Condition for execution

37

* @returns Spec that runs only if condition is true

38

*/

39

def when(b: Boolean): Spec[R, E, T]

40

41

/**

42

* Provide a layer to satisfy environment requirements

43

* @param layer - Layer providing required services

44

* @returns Spec with environment satisfied

45

*/

46

def provideSomeLayer[R0](layer: ZLayer[R0, Nothing, R]): Spec[R0, E, T]

47

48

/**

49

* Provide complete layer for environment

50

* @param layer - Layer providing all required services

51

* @returns Spec with complete environment

52

*/

53

def provideLayer[E1 >: E](layer: ZLayer[Any, E1, R]): Spec[Any, E1, T]

54

55

/**

56

* Map over the test results

57

* @param f - Function to transform test results

58

* @returns Spec with transformed results

59

*/

60

def map[T1](f: T => T1): Spec[R, E, T1]

61

62

/**

63

* Transform spec with access to environment and error information

64

* @param f - Transformation function

65

* @returns Transformed spec

66

*/

67

def transform[R1, E1, T1](f: Spec[R, E, T] => Spec[R1, E1, T1]): Spec[R1, E1, T1]

68

}

69

70

/**

71

* Companion object with spec creation utilities

72

*/

73

object Spec {

74

/**

75

* Create a labeled spec

76

* @param label - Description/name for the spec

77

* @param spec - Spec to label

78

* @returns Labeled spec

79

*/

80

def labeled[R, E, T](label: String, spec: Spec[R, E, T]): Spec[R, E, T]

81

82

/**

83

* Create a spec containing multiple child specs

84

* @param specs - Child specs to include

85

* @returns Combined spec

86

*/

87

def multiple[R, E, T](specs: Chunk[Spec[R, E, T]]): Spec[R, E, T]

88

89

/**

90

* Create a single test spec

91

* @param test - Test to include

92

* @param annotations - Test annotations

93

* @returns Spec containing the test

94

*/

95

def test[R, E, T](test: ZIO[R, E, T], annotations: TestAnnotationMap): Spec[R, E, T]

96

97

/**

98

* Create an empty spec

99

* @returns Empty spec that succeeds immediately

100

*/

101

def empty[R, E, T]: Spec[R, E, T]

102

}

103

```

104

105

### Runnable Specification Classes

106

107

Base classes for creating executable test specifications.

108

109

```scala { .api }

110

/**

111

* Base class for runnable test specifications

112

* @param R - Environment type required by tests

113

* @param E - Error type tests may produce

114

*/

115

abstract class RunnableSpec[R, E] {

116

/**

117

* The test specification to run

118

* @returns Root spec containing all tests

119

*/

120

def spec: ZSpec[R, E]

121

122

/**

123

* Test aspects to apply to all tests

124

* @returns List of aspects to apply

125

*/

126

def aspects: List[TestAspect[Nothing, R, Nothing, Any]] = Nil

127

128

/**

129

* Test runner for executing the specification

130

* @returns Runner configured for this spec

131

*/

132

def runner: TestRunner[R, E]

133

134

/**

135

* Platform-specific test runner selection

136

* @returns Platform-appropriate runner

137

*/

138

def platform: TestPlatform = TestPlatform.default

139

140

/**

141

* Bootstrap layer for setting up test environment

142

* @returns Layer providing test setup

143

*/

144

def bootstrap: ZLayer[Any, Nothing, TestLogger] = TestLogger.fromConsole

145

146

/**

147

* Execute the specification and produce results

148

* @param spec - Specification to run

149

* @returns Effect producing execution results

150

*/

151

private[zio] def runSpec(

152

spec: ZSpec[Environment, Failure]

153

): URIO[TestLogger with Clock, ExecutedSpec[Failure]]

154

}

155

156

/**

157

* Default runnable spec with standard test environment

158

*/

159

abstract class DefaultRunnableSpec extends RunnableSpec[TestEnvironment, Any] {

160

/**

161

* Default aspects applied to all tests

162

* @returns List including timeout warning aspect

163

*/

164

override def aspects: List[TestAspect[Nothing, TestEnvironment, Nothing, Any]] =

165

List(TestAspect.timeoutWarning(60.seconds))

166

167

/**

168

* Default test runner with test environment

169

* @returns Pre-configured runner

170

*/

171

override def runner: TestRunner[TestEnvironment, Any] =

172

defaultTestRunner

173

174

/**

175

* Convenience method for creating suites (delegates to package object)

176

* @param label - Suite name

177

* @param specs - Specs to include in suite

178

* @returns Suite spec

179

*/

180

def suite[R, E, T](label: String)(specs: Spec[R, E, T]*): Spec[R, E, T] =

181

zio.test.suite(label)(specs: _*)

182

183

/**

184

* Convenience method for creating tests (delegates to package object)

185

* @param label - Test name

186

* @param assertion - Test assertion

187

* @returns Test spec

188

*/

189

def test(label: String)(assertion: => TestResult): ZSpec[Any, Nothing] =

190

zio.test.test(label)(assertion)

191

192

/**

193

* Convenience method for creating effectful tests (delegates to package object)

194

* @param label - Test name

195

* @param assertion - Effectful test assertion

196

* @returns Effectful test spec

197

*/

198

def testM[R, E](label: String)(assertion: => ZIO[R, E, TestResult]): ZSpec[R, E] =

199

zio.test.testM(label)(assertion)

200

}

201

202

/**

203

* Mutable runnable spec for imperatively building test suites

204

*/

205

abstract class MutableRunnableSpec extends DefaultRunnableSpec {

206

/**

207

* Mutable collection of test specs

208

*/

209

private var _specs: List[ZSpec[TestEnvironment, Any]] = Nil

210

211

/**

212

* Add a spec to this runnable spec

213

* @param spec - Spec to add

214

*/

215

def +(spec: ZSpec[TestEnvironment, Any]): Unit = {

216

_specs = spec :: _specs

217

}

218

219

/**

220

* Get all added specs as a suite

221

* @returns Combined suite of all added specs

222

*/

223

final def spec: ZSpec[TestEnvironment, Any] =

224

if (_specs.isEmpty) suite("empty")()

225

else suite(getClass.getSimpleName)(_specs.reverse: _*)

226

}

227

228

/**

229

* Default mutable runnable spec

230

*/

231

abstract class DefaultMutableRunnableSpec extends MutableRunnableSpec

232

```

233

234

### Execution Framework

235

236

Classes for running and executing test specifications.

237

238

```scala { .api }

239

/**

240

* Test runner interface for executing specifications

241

* @param R - Environment type

242

* @param E - Error type

243

*/

244

trait TestRunner[+R, +E] {

245

/**

246

* Run a test specification

247

* @param spec - Specification to execute

248

* @returns Effect producing execution results

249

*/

250

def run[R1 <: R, E1 >: E](spec: ZSpec[R1, E1]): URIO[R1 with TestLogger with Clock, ExecutedSpec[E1]]

251

}

252

253

/**

254

* Test executor for managing test execution

255

* @param R - Environment type

256

* @param E - Error type

257

*/

258

trait TestExecutor[+R, +E] {

259

/**

260

* Execute a single test

261

* @param spec - Test specification

262

* @param defExec - Default execution strategy

263

* @returns Effect producing test results

264

*/

265

def run[R1 <: R, E1 >: E](

266

spec: ZSpec[R1, E1],

267

defExec: ExecutionStrategy

268

): ZIO[R1 with TestLogger, Nothing, ExecutedSpec[E1]]

269

}

270

271

/**

272

* Test executor companion with default implementations

273

*/

274

object TestExecutor {

275

/**

276

* Create default test executor

277

* @param environment - Test environment layer

278

* @returns Default executor

279

*/

280

def default[R](environment: ZLayer[Any, Nothing, R]): TestExecutor[R, Any]

281

}

282

```

283

284

### Test Platform Support

285

286

Platform-specific test execution support.

287

288

```scala { .api }

289

/**

290

* Test platform abstraction

291

*/

292

trait TestPlatform {

293

/**

294

* Check if running on JavaScript platform

295

*/

296

def isJS: Boolean

297

298

/**

299

* Check if running on JVM platform

300

*/

301

def isJVM: Boolean

302

303

/**

304

* Check if running on Native platform

305

*/

306

def isNative: Boolean

307

}

308

309

/**

310

* Test platform companion with defaults

311

*/

312

object TestPlatform {

313

/**

314

* Default platform detection

315

*/

316

val default: TestPlatform

317

318

/**

319

* Check if currently on JavaScript platform

320

*/

321

def isJS: Boolean

322

323

/**

324

* Check if currently on JVM platform

325

*/

326

def isJVM: Boolean

327

328

/**

329

* Check if currently on Native platform

330

*/

331

def isNative: Boolean

332

}

333

```

334

335

### Spec Composition and Utilities

336

337

Utilities for building and composing specifications.

338

339

```scala { .api }

340

/**

341

* Spec case representing different types of specifications

342

*/

343

sealed trait SpecCase[+R, +E, +T, +S]

344

345

object SpecCase {

346

/**

347

* Test case containing a single test

348

*/

349

final case class TestCase[+R, +E, +T](test: ZIO[R, E, T], annotations: TestAnnotationMap) extends SpecCase[R, E, T, Nothing]

350

351

/**

352

* Labeled case with description

353

*/

354

final case class LabeledCase[+S](label: String, spec: S) extends SpecCase[Nothing, Nothing, Nothing, S]

355

356

/**

357

* Multiple case containing child specs

358

*/

359

final case class MultipleCase[+S](specs: Chunk[S]) extends SpecCase[Nothing, Nothing, Nothing, S]

360

361

/**

362

* Managed case with resource management

363

*/

364

final case class ManagedCase[+R, +E, +S](managed: ZManaged[R, E, S]) extends SpecCase[R, E, Nothing, S]

365

}

366

```

367

368

**Usage Examples:**

369

370

```scala

371

// Basic runnable spec

372

object MyTests extends DefaultRunnableSpec {

373

def spec = suite("my application tests")(

374

suite("user management")(

375

test("create user") {

376

assert(createUser("john", "john@example.com"))(isSuccess)

377

},

378

testM("find user") {

379

for {

380

user <- createUser("jane", "jane@example.com")

381

found <- findUser(user.id)

382

} yield assert(found)(isSome(equalTo(user)))

383

}

384

),

385

suite("data processing")(

386

test("transform data") {

387

val input = List(1, 2, 3)

388

val expected = List(2, 4, 6)

389

assert(input.map(_ * 2))(equalTo(expected))

390

}

391

)

392

)

393

}

394

395

// Mutable spec for dynamic test construction

396

object DynamicTests extends MutableRunnableSpec {

397

// Add tests dynamically

398

for (i <- 1 to 5) {

399

this + test(s"dynamic test $i") {

400

assert(i * 2)(isGreaterThan(i))

401

}

402

}

403

404

// Add conditional tests

405

if (System.getProperty("run.integration.tests") == "true") {

406

this + suite("integration tests")(

407

testM("external service") {

408

for {

409

result <- callExternalService()

410

} yield assert(result)(isSuccess)

411

}

412

)

413

}

414

}

415

416

// Custom runnable spec with specific environment

417

abstract class DatabaseSpec extends RunnableSpec[Database with TestEnvironment, Any] {

418

override def aspects = List(

419

TestAspect.sequential, // Database tests run sequentially

420

TestAspect.timeout(30.seconds)

421

)

422

423

val databaseLayer: ZLayer[Any, Nothing, Database] = ???

424

425

override def runner = TestRunner(

426

TestExecutor.default(testEnvironment ++ databaseLayer)

427

)

428

429

// Helper methods for database tests

430

def withCleanDatabase[R, E, A](test: ZIO[R, E, A]): ZIO[R with Database, E, A] =

431

Database.cleanAll *> test

432

}

433

```

434

435

## Types

436

437

### Core Specification Types

438

439

```scala { .api }

440

/**

441

* Core spec type

442

*/

443

final case class Spec[-R, +E, +T](caseValue: SpecCase[R, E, T, Spec[R, E, T]])

444

445

/**

446

* ZIO Test specification type (most commonly used)

447

*/

448

type ZSpec[-R, +E] = Spec[R, TestFailure[E], TestSuccess]

449

450

/**

451

* Spec case variants

452

*/

453

sealed trait SpecCase[+R, +E, +T, +S]

454

```

455

456

### Execution Result Types

457

458

```scala { .api }

459

/**

460

* Results of executing a test specification

461

*/

462

final case class ExecutedSpec[+E](

463

caseValue: SpecCase[Any, E, TestSuccess, ExecutedSpec[E]]

464

) {

465

/**

466

* Fold over the execution results

467

*/

468

def fold[Z](

469

test: (TestSuccess, TestAnnotationMap) => Z,

470

labeled: (String, Z) => Z,

471

multiple: Chunk[Z] => Z,

472

managed: Z => Z

473

): Z

474

475

/**

476

* Check if all tests succeeded

477

*/

478

def isSuccess: Boolean

479

480

/**

481

* Get all test failures

482

*/

483

def failures: Chunk[TestFailure[E]]

484

485

/**

486

* Count total number of tests

487

*/

488

def size: Int

489

}

490

491

/**

492

* Summary of test execution results

493

*/

494

final case class Summary(

495

success: Int,

496

fail: Int,

497

ignore: Int,

498

summary: String

499

) {

500

/**

501

* Total number of tests

502

*/

503

def total: Int = success + fail + ignore

504

505

/**

506

* Whether all tests passed

507

*/

508

def isSuccess: Boolean = fail == 0

509

}

510

```

511

512

### Runner and Executor Types

513

514

```scala { .api }

515

/**

516

* Test runner interface

517

*/

518

trait TestRunner[+R, +E]

519

520

/**

521

* Test executor interface

522

*/

523

trait TestExecutor[+R, +E]

524

525

/**

526

* Execution strategy for running tests

527

*/

528

sealed trait ExecutionStrategy

529

object ExecutionStrategy {

530

case object Sequential extends ExecutionStrategy

531

case object Parallel extends ExecutionStrategy

532

case object ParallelN(n: Int) extends ExecutionStrategy

533

}

534

```