or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

async.mdfixtures.mdindex.mdmatchers.mdproperty.mdscalactic.mdtest-styles.md

fixtures.mddocs/

0

# Fixtures and Lifecycle

1

2

ScalaTest provides comprehensive support for test fixtures and suite lifecycle management, enabling setup and teardown operations, resource management, and data sharing between tests.

3

4

## Capabilities

5

6

### Before and After Each Test

7

8

Execute setup and cleanup code before and after each individual test.

9

10

```scala { .api }

11

trait BeforeAndAfterEach extends SuiteMixin {

12

13

/**

14

* Execute before each test method

15

*/

16

def beforeEach(): Unit = ()

17

18

/**

19

* Execute after each test method

20

*/

21

def afterEach(): Unit = ()

22

23

/**

24

* Override to customize the execution around each test

25

*/

26

abstract override def withFixture(test: NoArgTest): Outcome = {

27

beforeEach()

28

try super.withFixture(test)

29

finally afterEach()

30

}

31

}

32

```

33

34

**Usage Examples:**

35

36

```scala

37

import org.scalatest.funsuite.AnyFunSuite

38

import org.scalatest.BeforeAndAfterEach

39

40

class DatabaseSuite extends AnyFunSuite with BeforeAndAfterEach {

41

var database: Database = _

42

43

override def beforeEach(): Unit = {

44

database = new Database()

45

database.connect()

46

database.createTables()

47

}

48

49

override def afterEach(): Unit = {

50

database.dropTables()

51

database.disconnect()

52

database = null

53

}

54

55

test("should insert user") {

56

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

57

database.insert(user)

58

database.count("users") should equal (1)

59

}

60

61

test("should delete user") {

62

val user = User("Jane", "jane@example.com")

63

database.insert(user)

64

database.delete(user.id)

65

database.count("users") should equal (0)

66

}

67

}

68

```

69

70

### Before and After All Tests

71

72

Execute setup and cleanup code once before and after all tests in the suite.

73

74

```scala { .api }

75

trait BeforeAndAfterAll extends SuiteMixin {

76

77

/**

78

* Execute once before all tests in the suite

79

*/

80

def beforeAll(): Unit = ()

81

82

/**

83

* Execute once after all tests in the suite

84

*/

85

def afterAll(): Unit = ()

86

87

/**

88

* Override to customize suite-wide setup/teardown

89

*/

90

abstract override def run(testName: Option[String], args: Args): Status = {

91

if (!args.runTestInNewInstance) beforeAll()

92

try {

93

val status = super.run(testName, args)

94

status.waitUntilCompleted()

95

status

96

} finally {

97

if (!args.runTestInNewInstance) afterAll()

98

}

99

}

100

}

101

```

102

103

**Usage Examples:**

104

105

```scala

106

import org.scalatest.funsuite.AnyFunSuite

107

import org.scalatest.BeforeAndAfterAll

108

109

class ServerSuite extends AnyFunSuite with BeforeAndAfterAll {

110

var server: TestServer = _

111

112

override def beforeAll(): Unit = {

113

server = new TestServer(port = 8080)

114

server.start()

115

server.waitUntilReady()

116

}

117

118

override def afterAll(): Unit = {

119

server.stop()

120

server.waitUntilStopped()

121

}

122

123

test("server should respond to health check") {

124

val response = httpGet(s"http://localhost:8080/health")

125

response.status should equal (200)

126

response.body should include ("OK")

127

}

128

129

test("server should handle API requests") {

130

val response = httpPost(s"http://localhost:8080/api/users", """{"name": "test"}""")

131

response.status should equal (201)

132

}

133

}

134

```

135

136

### Fixture Test Suites

137

138

Share fixtures between tests using parameterized test functions.

139

140

```scala { .api }

141

trait FixtureTestSuite extends TestSuite {

142

143

/**

144

* The type of fixture object passed to tests

145

*/

146

type FixtureParam

147

148

/**

149

* Create and cleanup fixture for each test

150

*/

151

def withFixture(test: OneArgTest): Outcome

152

153

/**

154

* Run a single test with fixture

155

*/

156

def runTest(testName: String, args: Args): Status = {

157

val oneArgTest = new OneArgTest {

158

val name = testName

159

def apply(fixture: FixtureParam): Outcome = {

160

// Test implementation provided by concrete suite

161

}

162

}

163

withFixture(oneArgTest).toStatus

164

}

165

}

166

167

/**

168

* Fixture-enabled FunSuite

169

*/

170

abstract class FixtureAnyFunSuite extends FixtureTestSuite with TestRegistration {

171

172

/**

173

* Register a test that requires a fixture

174

*/

175

protected def test(testName: String)(testFun: FixtureParam => Any): Unit

176

}

177

```

178

179

**Usage Examples:**

180

181

```scala

182

import org.scalatest.fixture.AnyFunSuite

183

import java.io.{File, FileWriter}

184

185

class FileFixtureSuite extends AnyFunSuite {

186

187

// Fixture is a temporary file

188

type FixtureParam = File

189

190

def withFixture(test: OneArgTest): Outcome = {

191

val tempFile = File.createTempFile("test", ".txt")

192

193

try {

194

// Setup: write initial content

195

val writer = new FileWriter(tempFile)

196

writer.write("initial content")

197

writer.close()

198

199

// Run test with fixture

200

test(tempFile)

201

} finally {

202

// Cleanup: delete temp file

203

tempFile.delete()

204

}

205

}

206

207

test("should read file content") { file =>

208

val content = scala.io.Source.fromFile(file).mkString

209

content should include ("initial")

210

}

211

212

test("should append to file") { file =>

213

val writer = new FileWriter(file, true) // append mode

214

writer.write("\nappended content")

215

writer.close()

216

217

val content = scala.io.Source.fromFile(file).mkString

218

content should include ("appended")

219

}

220

}

221

```

222

223

### Fixture Context

224

225

Lightweight fixture sharing using traits.

226

227

```scala { .api }

228

trait FixtureContext {

229

// Define fixture data and helper methods as trait members

230

}

231

```

232

233

**Usage Examples:**

234

235

```scala

236

import org.scalatest.funsuite.AnyFunSuite

237

238

class ContextFixtureSuite extends AnyFunSuite {

239

240

trait DatabaseContext {

241

val database = new InMemoryDatabase()

242

database.createSchema()

243

244

val testUser = User("testuser", "test@example.com")

245

database.insert(testUser)

246

247

def findUser(name: String): Option[User] = database.findByName(name)

248

}

249

250

trait ApiContext {

251

val baseUrl = "http://test.example.com"

252

val apiKey = "test-api-key"

253

254

def makeRequest(endpoint: String): HttpResponse = {

255

// Mock HTTP request implementation

256

HttpResponse(200, s"Response from $endpoint")

257

}

258

}

259

260

test("should find existing user") {

261

new DatabaseContext {

262

findUser("testuser") should be (defined)

263

findUser("nonexistent") should be (empty)

264

}

265

}

266

267

test("should handle API requests") {

268

new ApiContext {

269

val response = makeRequest("/users")

270

response.status should equal (200)

271

response.body should include ("Response from /users")

272

}

273

}

274

275

test("should combine contexts") {

276

new DatabaseContext with ApiContext {

277

// Use both database and API fixtures

278

val user = findUser("testuser").get

279

val response = makeRequest(s"/users/${user.id}")

280

response.status should equal (200)

281

}

282

}

283

}

284

```

285

286

### Test Data and Config Map

287

288

Access configuration and test data through the Args parameter.

289

290

```scala { .api }

291

trait BeforeAndAfterEachTestData extends SuiteMixin {

292

293

/**

294

* Execute before each test with access to test data

295

*/

296

def beforeEach(testData: TestData): Unit = ()

297

298

/**

299

* Execute after each test with access to test data

300

*/

301

def afterEach(testData: TestData): Unit = ()

302

303

abstract override def withFixture(test: NoArgTest): Outcome = {

304

beforeEach(test)

305

try super.withFixture(test)

306

finally afterEach(test)

307

}

308

}

309

310

trait BeforeAndAfterAllConfigMap extends SuiteMixin {

311

312

/**

313

* Execute before all tests with access to config map

314

*/

315

def beforeAll(configMap: ConfigMap): Unit = ()

316

317

/**

318

* Execute after all tests with access to config map

319

*/

320

def afterAll(configMap: ConfigMap): Unit = ()

321

}

322

323

/**

324

* Test metadata and configuration

325

*/

326

trait TestData {

327

val name: String

328

val scopes: Vector[String]

329

val text: String

330

val tags: Set[String]

331

val pos: Option[source.Position]

332

}

333

334

/**

335

* Configuration map for test execution

336

*/

337

class ConfigMap(map: Map[String, Any]) {

338

def apply(key: String): Any = map(key)

339

def get(key: String): Option[Any] = map.get(key)

340

def contains(key: String): Boolean = map.contains(key)

341

def ++(other: ConfigMap): ConfigMap = new ConfigMap(map ++ other.map)

342

}

343

```

344

345

**Usage Examples:**

346

347

```scala

348

import org.scalatest.funsuite.AnyFunSuite

349

import org.scalatest.{BeforeAndAfterEachTestData, BeforeAndAfterAllConfigMap}

350

351

class ConfigurableSuite extends AnyFunSuite

352

with BeforeAndAfterEachTestData

353

with BeforeAndAfterAllConfigMap {

354

355

var globalConfig: String = _

356

357

override def beforeAll(configMap: ConfigMap): Unit = {

358

globalConfig = configMap.getOrElse("environment", "test").toString

359

println(s"Running tests in $globalConfig environment")

360

}

361

362

override def beforeEach(testData: TestData): Unit = {

363

println(s"Starting test: ${testData.name}")

364

if (testData.tags.contains("slow")) {

365

println("This is a slow test, please be patient...")

366

}

367

}

368

369

override def afterEach(testData: TestData): Unit = {

370

println(s"Completed test: ${testData.name}")

371

}

372

373

test("should use global config") {

374

globalConfig should not be empty

375

// Test implementation using globalConfig

376

}

377

378

test("slow database operation", SlowTest) {

379

// This test will get special logging due to the SlowTest tag

380

Thread.sleep(100) // Simulate slow operation

381

succeed

382

}

383

}

384

385

// Custom tag for marking slow tests

386

object SlowTest extends Tag("org.example.SlowTest")

387

```

388

389

## Types

390

391

```scala { .api }

392

/**

393

* Test function that receives no fixture parameter

394

*/

395

trait NoArgTest extends (() => Outcome) with TestData {

396

def apply(): Outcome

397

val name: String

398

val scopes: Vector[String]

399

val text: String

400

val tags: Set[String]

401

}

402

403

/**

404

* Test function that receives one fixture parameter

405

*/

406

trait OneArgTest extends (FixtureParam => Outcome) with TestData {

407

def apply(fixture: FixtureParam): Outcome

408

val name: String

409

val scopes: Vector[String]

410

val text: String

411

val tags: Set[String]

412

}

413

414

/**

415

* Mixin trait for suites that can be mixed into other suites

416

*/

417

trait SuiteMixin { this: Suite =>

418

// Mixed into Suite to provide additional functionality

419

}

420

421

/**

422

* Test outcome representing the result of running a test

423

*/

424

sealed abstract class Outcome extends Product with Serializable {

425

def isSucceeded: Boolean

426

def isFailed: Boolean

427

def isCanceled: Boolean

428

def isPending: Boolean

429

def toStatus: Status

430

}

431

432

case object Succeeded extends Outcome

433

final case class Failed(exception: Throwable) extends Outcome

434

final case class Canceled(exception: Throwable) extends Outcome

435

case object Pending extends Outcome

436

```