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

mock-testing.mddocs/

0

# Mock Testing Framework

1

2

Service mocking system with expectation-based testing for ZIO services. The mock framework allows testing components in isolation by providing controlled implementations of their dependencies.

3

4

## Capabilities

5

6

### Core Mock Classes

7

8

Foundation classes for creating and using mocks.

9

10

```scala { .api }

11

/**

12

* Base trait for creating mock implementations of ZIO services

13

*/

14

trait Mock[R] {

15

/**

16

* The environment type this mock provides

17

*/

18

type Environment = R

19

}

20

21

/**

22

* Represents an expectation for a service method call

23

*/

24

abstract class Expectation[R] {

25

/**

26

* Combine this expectation with another using logical AND

27

*/

28

def &&[R1 <: R](that: Expectation[R1]): Expectation[R1]

29

30

/**

31

* Combine this expectation with another using logical OR

32

*/

33

def ||[R1 <: R](that: Expectation[R1]): Expectation[R1]

34

35

/**

36

* Repeat this expectation N times

37

*/

38

def repeats(range: Range): Expectation[R]

39

40

/**

41

* Make this expectation optional (may not be called)

42

*/

43

def optional: Expectation[R]

44

}

45

46

/**

47

* Represents a capability/method that can be mocked

48

*/

49

sealed trait Capability[R, I, E, A] {

50

/**

51

* The service type this capability belongs to

52

*/

53

type Service = R

54

55

/**

56

* Input parameters type

57

*/

58

type Input = I

59

60

/**

61

* Error type

62

*/

63

type Error = E

64

65

/**

66

* Return type

67

*/

68

type Output = A

69

}

70

71

/**

72

* Result that a mock method can return

73

*/

74

sealed trait Result[+E, +A]

75

76

object Result {

77

/**

78

* Successful result with value

79

*/

80

def succeed[A](value: A): Result[Nothing, A]

81

82

/**

83

* Failed result with error

84

*/

85

def fail[E](error: E): Result[E, Nothing]

86

87

/**

88

* Result that dies with exception

89

*/

90

def die(throwable: Throwable): Result[Nothing, Nothing]

91

92

/**

93

* Unit success result

94

*/

95

val unit: Result[Nothing, Unit]

96

}

97

```

98

99

### Built-in Mock Services

100

101

Pre-built mocks for standard ZIO services.

102

103

```scala { .api }

104

/**

105

* Mock implementation of ZIO Clock service

106

*/

107

object MockClock extends Mock[Clock] {

108

// Clock capabilities

109

object CurrentTime extends Capability[Clock, TimeUnit, Nothing, Long]

110

object CurrentDateTime extends Capability[Clock, Any, Nothing, OffsetDateTime]

111

object NanoTime extends Capability[Clock, Any, Nothing, Long]

112

object Sleep extends Capability[Clock, Duration, Nothing, Unit]

113

114

// Expectation builders

115

def currentTime(timeUnit: TimeUnit): Expectation[Clock]

116

def currentDateTime: Expectation[Clock]

117

def nanoTime: Expectation[Clock]

118

def sleep(duration: Duration): Expectation[Clock]

119

}

120

121

/**

122

* Mock implementation of ZIO Console service

123

*/

124

object MockConsole extends Mock[Console] {

125

// Console capabilities

126

object PutStr extends Capability[Console, String, IOException, Unit]

127

object PutStrLn extends Capability[Console, String, IOException, Unit]

128

object PutStrErr extends Capability[Console, String, IOException, Unit]

129

object PutStrLnErr extends Capability[Console, String, IOException, Unit]

130

object GetStrLn extends Capability[Console, Any, IOException, String]

131

132

// Expectation builders

133

def putStr(line: String): Expectation[Console]

134

def putStrLn(line: String): Expectation[Console]

135

def putStrErr(line: String): Expectation[Console]

136

def putStrLnErr(line: String): Expectation[Console]

137

def getStrLn: Expectation[Console]

138

}

139

140

/**

141

* Mock implementation of ZIO Random service

142

*/

143

object MockRandom extends Mock[Random] {

144

// Random capabilities

145

object NextBoolean extends Capability[Random, Any, Nothing, Boolean]

146

object NextBytes extends Capability[Random, Int, Nothing, Chunk[Byte]]

147

object NextDouble extends Capability[Random, Any, Nothing, Double]

148

object NextDoubleBetween extends Capability[Random, (Double, Double), Nothing, Double]

149

object NextFloat extends Capability[Random, Any, Nothing, Float]

150

object NextFloatBetween extends Capability[Random, (Float, Float), Nothing, Float]

151

object NextGaussian extends Capability[Random, Any, Nothing, Double]

152

object NextInt extends Capability[Random, Any, Nothing, Int]

153

object NextIntBetween extends Capability[Random, (Int, Int), Nothing, Int]

154

object NextIntBounded extends Capability[Random, Int, Nothing, Int]

155

object NextLong extends Capability[Random, Any, Nothing, Long]

156

object NextLongBetween extends Capability[Random, (Long, Long), Nothing, Long]

157

object NextLongBounded extends Capability[Random, Long, Nothing, Long]

158

object NextPrintableChar extends Capability[Random, Any, Nothing, Char]

159

object NextString extends Capability[Random, Int, Nothing, String]

160

object NextUUID extends Capability[Random, Any, Nothing, UUID]

161

object Shuffle extends Capability[Random, List[Any], Nothing, List[Any]]

162

163

// Expectation builders (examples)

164

def nextBoolean: Expectation[Random]

165

def nextInt: Expectation[Random]

166

def nextIntBetween(min: Int, max: Int): Expectation[Random]

167

def nextString(length: Int): Expectation[Random]

168

}

169

170

/**

171

* Mock implementation of ZIO System service

172

*/

173

object MockSystem extends Mock[System] {

174

// System capabilities

175

object Property extends Capability[System, String, Throwable, Option[String]]

176

object PropertyOrElse extends Capability[System, (String, String), Throwable, String]

177

object PropertyOrOption extends Capability[System, (String, Option[String]), Throwable, Option[String]]

178

object Env extends Capability[System, String, SecurityException, Option[String]]

179

object EnvOrElse extends Capability[System, (String, String), SecurityException, String]

180

object EnvOrOption extends Capability[System, (String, Option[String]), SecurityException, Option[String]]

181

object LineSeparator extends Capability[System, Any, Nothing, String]

182

183

// Expectation builders

184

def property(name: String): Expectation[System]

185

def env(name: String): Expectation[System]

186

def lineSeparator: Expectation[System]

187

}

188

```

189

190

### Expectation Creation and Configuration

191

192

Building expectations for mock method calls.

193

194

```scala { .api }

195

/**

196

* Create expectation that method will be called and return specified result

197

*/

198

def expect[R, I, E, A](capability: Capability[R, I, E, A])(assertion: Assertion[I], result: Result[E, A]): Expectation[R]

199

200

/**

201

* Create expectation with input matching

202

*/

203

def expect[R, I, E, A](capability: Capability[R, I, E, A])(input: I, result: Result[E, A]): Expectation[R]

204

205

/**

206

* Create expectation with input assertion and effectful result

207

*/

208

def expectM[R, I, E, A](capability: Capability[R, I, E, A])(assertion: Assertion[I], result: ZIO[Any, E, A]): Expectation[R]

209

```

210

211

**Expectation Modifiers:**

212

213

```scala { .api }

214

// Repetition control

215

expectation.repeats(1 to 3) // Called 1-3 times

216

expectation.repeats(Range.atLeast(2)) // Called at least 2 times

217

expectation.repeats(Range.exactly(1)) // Called exactly once

218

219

// Optional calls

220

expectation.optional // May or may not be called

221

222

// Logical combination

223

expectation1 && expectation2 // Both must be satisfied

224

expectation1 || expectation2 // Either can be satisfied

225

```

226

227

**Usage Examples:**

228

229

```scala

230

import zio.test.mock._

231

import zio.test.mock.Expectation._

232

233

// Simple mock expectation

234

val consoleMock = MockConsole.putStrLn(equalTo("Hello")) returns unit

235

236

// Multiple expectations

237

val clockMock =

238

MockClock.currentTime(equalTo(TimeUnit.MILLISECONDS)) returns value(1234567890L) &&

239

MockClock.sleep(equalTo(1.second)) returns unit

240

241

// Repeated calls

242

val randomMock = MockRandom.nextInt returns value(42) repeats (1 to 5)

243

244

// Complex assertions

245

val systemMock = MockSystem.property(startsWith("java.")) returns value(Some("value"))

246

```

247

248

### Mock Environment Creation

249

250

Creating mock environments for testing.

251

252

```scala { .api }

253

/**

254

* Create a mock environment layer from expectations

255

*/

256

def expectation[R: Tag](expectations: Expectation[R]*): ULayer[R]

257

258

/**

259

* Run test with mock environment

260

*/

261

def withMock[R: Tag, E, A](expectations: Expectation[R]*)(test: ZIO[R, E, A]): ZIO[Any, E, A]

262

```

263

264

**Usage Examples:**

265

266

```scala

267

import zio.test._

268

import zio.test.mock._

269

270

// Test with mock console

271

testM("greeting program") {

272

val mock = MockConsole.putStrLn(equalTo("Hello, World!")) returns unit

273

274

val program = putStrLn("Hello, World!")

275

276

program.provideLayer(MockConsole.expectation(mock))

277

}

278

279

// Multiple service mocks

280

testM("complex program") {

281

val consoleMock = MockConsole.putStrLn(anything) returns unit

282

val clockMock = MockClock.currentTime(anything) returns value(System.currentTimeMillis())

283

val randomMock = MockRandom.nextInt returns value(42)

284

285

val program = for {

286

time <- currentTime(TimeUnit.MILLISECONDS)

287

rand <- nextInt

288

_ <- putStrLn(s"Time: $time, Random: $rand")

289

} yield ()

290

291

program.provideLayer(

292

MockConsole.expectation(consoleMock) ++

293

MockClock.expectation(clockMock) ++

294

MockRandom.expectation(randomMock)

295

)

296

}

297

```

298

299

### Custom Mock Creation

300

301

Creating mocks for your own services.

302

303

```scala { .api }

304

/**

305

* Macro for generating mock implementations of services

306

*/

307

@mockable

308

trait UserService {

309

def getUser(id: String): IO[UserError, User]

310

def createUser(name: String, email: String): IO[UserError, User]

311

def deleteUser(id: String): IO[UserError, Unit]

312

}

313

314

// Generated mock object

315

object MockUserService extends Mock[UserService] {

316

object GetUser extends Capability[UserService, String, UserError, User]

317

object CreateUser extends Capability[UserService, (String, String), UserError, User]

318

object DeleteUser extends Capability[UserService, String, UserError, Unit]

319

320

def getUser(id: String): Expectation[UserService]

321

def createUser(name: String, email: String): Expectation[UserService]

322

def deleteUser(id: String): Expectation[UserService]

323

}

324

```

325

326

**Custom Mock Usage:**

327

328

```scala

329

// Test user repository with mock service

330

testM("user repository test") {

331

val user = User("123", "John", "john@example.com")

332

333

val userServiceMock =

334

MockUserService.getUser(equalTo("123")) returns value(user) &&

335

MockUserService.createUser(equalTo("Jane"), equalTo("jane@example.com")) returns value(User("124", "Jane", "jane@example.com"))

336

337

val repository = new UserRepository()

338

339

for {

340

retrieved <- repository.findUser("123")

341

created <- repository.addUser("Jane", "jane@example.com")

342

} yield assert(retrieved)(equalTo(user)) && assert(created.name)(equalTo("Jane"))

343

}.provideLayer(MockUserService.expectation(userServiceMock))

344

```

345

346

### Proxy and Internal Classes

347

348

Internal mock framework classes for advanced usage.

349

350

```scala { .api }

351

/**

352

* Proxy interface for mock implementations

353

*/

354

trait Proxy[M] {

355

def invoke[I, E, A](capability: Capability[M, I, E, A], input: I): ZIO[Any, E, A]

356

}

357

358

/**

359

* Mock state management

360

*/

361

object MockState {

362

def make: UIO[Ref[MockState]]

363

def checkUnmatched: ZIO[Any, UnmatchedExpectations, Unit]

364

def satisfied: UIO[Boolean]

365

}

366

367

/**

368

* Mock exceptions for expectation violations

369

*/

370

sealed trait MockException extends Exception

371

372

case class UnexpectedCall[I](capability: String, input: I) extends MockException

373

case class InvalidCall[I](capability: String, input: I, assertion: String) extends MockException

374

case class UnmatchedExpectations(expectations: List[String]) extends MockException

375

```

376

377

## Types

378

379

### Core Mock Types

380

381

```scala { .api }

382

/**

383

* Base mock trait

384

*/

385

trait Mock[R] {

386

type Environment = R

387

}

388

389

/**

390

* Test expectation for service method calls

391

*/

392

abstract class Expectation[R]

393

394

/**

395

* Service capability that can be mocked

396

*/

397

sealed trait Capability[R, I, E, A]

398

399

/**

400

* Result of mock method call

401

*/

402

sealed trait Result[+E, +A]

403

```

404

405

### Mock State Types

406

407

```scala { .api }

408

/**

409

* Internal state of mock system

410

*/

411

final case class MockState(

412

expectations: List[ExpectationState],

413

calls: List[CallLog]

414

)

415

416

/**

417

* State of individual expectation

418

*/

419

sealed trait ExpectationState

420

case class Pending(expectation: Expectation[Any]) extends ExpectationState

421

case class Matched(expectation: Expectation[Any], callCount: Int) extends ExpectationState

422

423

/**

424

* Log of mock method calls

425

*/

426

case class CallLog(

427

capability: String,

428

input: Any,

429

result: Either[Throwable, Any]

430

)

431

```

432

433

### Range Types for Repetition

434

435

```scala { .api }

436

/**

437

* Range specification for expectation repetition

438

*/

439

sealed trait Range

440

object Range {

441

def exactly(n: Int): Range

442

def atLeast(n: Int): Range

443

def atMost(n: Int): Range

444

def between(min: Int, max: Int): Range

445

}

446

```