or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

advanced.mdassertions.mdasync.mdfixtures.mdindex.mdmatchers.mdtest-styles.md

assertions.mddocs/

0

# Assertions

1

2

ScalaTest's assertion framework provides the foundation for all test verification with enhanced error reporting, stack trace management, and integration with the matcher system. The framework distinguishes between assertions (which fail tests) and assumptions (which cancel tests when conditions aren't met).

3

4

## Capabilities

5

6

### Core Assertions

7

8

The fundamental assertion methods available in all test suites through the `Assertions` trait.

9

10

```scala { .api }

11

/**

12

* Core assertion methods for test verification

13

*/

14

trait Assertions {

15

/**

16

* Assert that a boolean condition is true

17

* @param condition the boolean condition to check

18

* @throws TestFailedException if condition is false

19

*/

20

def assert(condition: Boolean): Assertion

21

22

/**

23

* Assert that a boolean condition is true with additional clue

24

* @param condition the boolean condition to check

25

* @param clue additional information displayed on failure

26

*/

27

def assert(condition: Boolean, clue: Any): Assertion

28

29

/**

30

* Assert that actual value equals expected value

31

* @param expected the expected value

32

* @param actual the actual value to compare

33

*/

34

def assertResult[T](expected: T)(actual: T): Assertion

35

36

/**

37

* Assert that executing code throws expected exception type

38

* @param f the code block that should throw

39

* @return the thrown exception

40

*/

41

def assertThrows[T <: AnyRef](f: => Any): T

42

43

/**

44

* Fail the test immediately with default message

45

*/

46

def fail(): Nothing

47

48

/**

49

* Fail the test immediately with custom message

50

* @param message the failure message

51

*/

52

def fail(message: String): Nothing

53

54

/**

55

* Cancel the test (different from failure - indicates test couldn't run)

56

*/

57

def cancel(): Nothing

58

59

/**

60

* Cancel the test with message

61

* @param message the cancellation reason

62

*/

63

def cancel(message: String): Nothing

64

65

/**

66

* Mark test as pending (not yet implemented)

67

*/

68

def pending: Assertion with PendingStatement

69

70

/**

71

* Explicit success assertion (useful in some contexts)

72

*/

73

def succeed: Assertion

74

}

75

```

76

77

**Usage Examples:**

78

79

```scala

80

import org.scalatest.funsuite.AnyFunSuite

81

import org.scalatest.Assertions

82

83

class AssertionExamplesSpec extends AnyFunSuite {

84

85

test("basic assertions") {

86

val x = 5

87

val y = 3

88

89

// Simple boolean assertion

90

assert(x > y)

91

assert(x > 0, "x should be positive")

92

93

// Value comparison

94

assertResult(8) {

95

x + y

96

}

97

98

// Exception assertion

99

assertThrows[ArithmeticException] {

100

x / 0

101

}

102

}

103

104

test("test lifecycle control") {

105

val config = loadTestConfiguration()

106

107

if (config.isEmpty) {

108

cancel("Configuration not available - test cannot run")

109

}

110

111

// Test continues only if config is available

112

processWithConfig(config.get)

113

succeed // Explicit success

114

}

115

116

test("pending implementation") {

117

// Test placeholder for future implementation

118

pending

119

}

120

}

121

```

122

123

### Enhanced Assertions with Clues

124

125

Add contextual information to assertion failures using `AppendedClues` trait.

126

127

```scala { .api }

128

/**

129

* Provides withClue method for adding context to assertions

130

*/

131

trait AppendedClues {

132

/**

133

* Execute assertion with additional clue information

134

* @param clue contextual information for failure messages

135

* @param fun assertion code block

136

*/

137

def withClue[T](clue: Any)(fun: => T): T

138

}

139

```

140

141

**Usage Example:**

142

143

```scala

144

import org.scalatest.funsuite.AnyFunSuite

145

import org.scalatest.matchers.should.Matchers

146

import org.scalatest.AppendedClues

147

148

class ClueExamplesSpec extends AnyFunSuite with Matchers with AppendedClues {

149

150

test("assertions with contextual clues") {

151

val users = loadUsers()

152

val activeUsers = users.filter(_.isActive)

153

154

withClue(s"Total users: ${users.size}, Active: ${activeUsers.size}") {

155

activeUsers.size should be > 0

156

}

157

158

for ((user, index) <- users.zipWithIndex) {

159

withClue(s"User at index $index: ${user.name}") {

160

user.email should not be empty

161

user.age should be >= 0

162

}

163

}

164

}

165

}

166

```

167

168

### Non-Implicit Assertions

169

170

Use `NonImplicitAssertions` when you want to avoid implicit conversions that enable the matcher DSL.

171

172

```scala { .api }

173

/**

174

* Assertion methods without implicit conversions to matchers

175

*/

176

trait NonImplicitAssertions {

177

def assert(condition: Boolean): Assertion

178

def assert(condition: Boolean, clue: Any): Assertion

179

def assertResult[T](expected: T)(actual: T): Assertion

180

def assertThrows[T <: AnyRef](f: => Any): T

181

// ... other assertion methods without matcher support

182

}

183

```

184

185

### Assumptions

186

187

Assumptions cancel tests when preconditions aren't met, different from assertions which fail tests.

188

189

```scala { .api }

190

/**

191

* Assumption methods for conditional test execution

192

*/

193

def assume(condition: Boolean): Assertion

194

def assume(condition: Boolean, clue: Any): Assertion

195

def cancel(): Nothing

196

def cancel(message: String): Nothing

197

```

198

199

**Usage Example:**

200

201

```scala

202

import org.scalatest.funsuite.AnyFunSuite

203

204

class DatabaseIntegrationSpec extends AnyFunSuite {

205

206

test("database operations require connection") {

207

val dbAvailable = checkDatabaseConnection()

208

209

// Cancel test if database isn't available (not a test failure)

210

assume(dbAvailable, "Database connection not available")

211

212

// Test continues only if database is available

213

val result = performDatabaseOperation()

214

assert(result.isSuccess)

215

}

216

}

217

```

218

219

### Enhanced Value Access

220

221

Safely access contents of common Scala types with helpful error messages.

222

223

```scala { .api }

224

/**

225

* Safe access to Option contents

226

*/

227

trait OptionValues {

228

implicit def convertOptionToValuable[T](opt: Option[T]): OptionValuable[T]

229

230

final class OptionValuable[T](opt: Option[T]) {

231

/**

232

* Get the value from Some, or fail with descriptive message for None

233

*/

234

def value: T

235

}

236

}

237

238

/**

239

* Safe access to Either contents

240

*/

241

trait EitherValues {

242

implicit def convertEitherToValuable[L, R](either: Either[L, R]): EitherValuable[L, R]

243

244

final class EitherValuable[L, R](either: Either[L, R]) {

245

def left: LeftValuable[L, R]

246

def right: RightValuable[L, R]

247

}

248

249

final class LeftValuable[L, R](either: Either[L, R]) {

250

def value: L // Fails if Either is Right

251

}

252

253

final class RightValuable[L, R](either: Either[L, R]) {

254

def value: R // Fails if Either is Left

255

}

256

}

257

258

/**

259

* Safe access to Try contents

260

*/

261

trait TryValues {

262

implicit def convertTryToSuccessOrFailure[T](t: Try[T]): TryValuable[T]

263

264

final class TryValuable[T](t: Try[T]) {

265

def success: SuccessValuable[T]

266

def failure: FailureValuable

267

}

268

269

final class SuccessValuable[T](t: Try[T]) {

270

def value: T // Fails if Try is Failure

271

}

272

273

final class FailureValuable(t: Try[_]) {

274

def exception: Throwable // Fails if Try is Success

275

}

276

}

277

278

/**

279

* Safe access to partial function behavior

280

*/

281

trait PartialFunctionValues {

282

implicit def convertPartialFunctionToValuable[A, B](pf: PartialFunction[A, B]): PartialFunctionValuable[A, B]

283

284

final class PartialFunctionValuable[A, B](pf: PartialFunction[A, B]) {

285

/**

286

* Apply partial function or fail with descriptive message

287

*/

288

def valueAt(x: A): B

289

}

290

}

291

292

/**

293

* Assert collections contain exactly one element

294

*/

295

trait LoneElement {

296

implicit def convertToCollectionLoneElementWrapper[E, C[_]](collection: C[E])(implicit conv: C[E] => Iterable[E]): CollectionLoneElementWrapper[C]

297

298

final class CollectionLoneElementWrapper[C[_]](collection: C[_]) {

299

/**

300

* Get the single element, or fail if empty or multiple elements

301

*/

302

def loneElement: Any

303

}

304

}

305

```

306

307

**Usage Examples:**

308

309

```scala

310

import org.scalatest.funsuite.AnyFunSuite

311

import org.scalatest.matchers.should.Matchers

312

import org.scalatest.{OptionValues, EitherValues, TryValues, PartialFunctionValues, LoneElement}

313

import scala.util.{Try, Success, Failure}

314

315

class ValueAccessSpec extends AnyFunSuite with Matchers

316

with OptionValues with EitherValues with TryValues

317

with PartialFunctionValues with LoneElement {

318

319

test("safe Option access") {

320

val someValue = Some("hello")

321

val noneValue = None

322

323

someValue.value should equal("hello")

324

325

// This would fail with descriptive message:

326

// noneValue.value should equal("anything")

327

}

328

329

test("safe Either access") {

330

val rightValue: Either[String, Int] = Right(42)

331

val leftValue: Either[String, Int] = Left("error")

332

333

rightValue.right.value should equal(42)

334

leftValue.left.value should equal("error")

335

336

// These would fail with descriptive messages:

337

// rightValue.left.value

338

// leftValue.right.value

339

}

340

341

test("safe Try access") {

342

val success: Try[Int] = Success(42)

343

val failure: Try[Int] = Failure(new RuntimeException("oops"))

344

345

success.success.value should equal(42)

346

failure.failure.exception.getMessage should equal("oops")

347

}

348

349

test("partial function testing") {

350

val pf: PartialFunction[Int, String] = {

351

case x if x > 0 => s"positive: $x"

352

}

353

354

pf.valueAt(5) should equal("positive: 5")

355

356

// This would fail with descriptive message:

357

// pf.valueAt(-1) should equal("anything")

358

}

359

360

test("lone element access") {

361

val singleItem = List("only")

362

val multipleItems = List("first", "second")

363

val emptyList = List.empty[String]

364

365

singleItem.loneElement should equal("only")

366

367

// These would fail with descriptive messages:

368

// multipleItems.loneElement

369

// emptyList.loneElement

370

}

371

}

372

```

373

374

### Exception Handling and Stack Traces

375

376

Control how exceptions and stack traces are handled in test failures.

377

378

```scala { .api }

379

/**

380

* Control stack trace display in test failures

381

*/

382

trait SeveredStackTraces {

383

// Automatically shortens stack traces to focus on relevant test code

384

}

385

386

/**

387

* Handle exceptions during test reporting

388

*/

389

trait CatchReporter {

390

// Catches and reports exceptions that occur during test reporting

391

}

392

```

393

394

### Custom Assertion Helpers

395

396

Create reusable assertion helpers for domain-specific testing.

397

398

**Usage Example:**

399

400

```scala

401

import org.scalatest.funsuite.AnyFunSuite

402

import org.scalatest.matchers.should.Matchers

403

import org.scalatest.Assertion

404

405

class CustomAssertionSpec extends AnyFunSuite with Matchers {

406

407

// Custom assertion helper

408

def assertValidEmail(email: String): Assertion = {

409

withClue(s"Invalid email format: '$email'") {

410

assert(email.contains("@"), "Email must contain @")

411

assert(email.contains("."), "Email must contain domain")

412

assert(!email.startsWith("@"), "Email cannot start with @")

413

assert(!email.endsWith("@"), "Email cannot end with @")

414

}

415

}

416

417

// Another custom helper

418

def assertBetween[T](value: T, min: T, max: T)(implicit ord: Ordering[T]): Assertion = {

419

withClue(s"Value $value not between $min and $max") {

420

assert(ord.gteq(value, min) && ord.lteq(value, max))

421

}

422

}

423

424

test("custom assertions in action") {

425

assertValidEmail("user@example.com")

426

assertBetween(5, 1, 10)

427

assertBetween(2.5, 2.0, 3.0)

428

429

// These would fail:

430

// assertValidEmail("invalid-email")

431

// assertBetween(15, 1, 10)

432

}

433

}

434

```

435

436

## Common Patterns

437

438

### Testing Exceptions

439

440

```scala

441

// Test that specific exception is thrown

442

assertThrows[IllegalArgumentException] {

443

new BankAccount(-100) // negative balance

444

}

445

446

// Capture and inspect the exception

447

val exception = assertThrows[ValidationException] {

448

validator.validate(invalidData)

449

}

450

exception.getMessage should include("required field")

451

exception.getFieldName should equal("email")

452

```

453

454

### Conditional Testing

455

456

```scala

457

// Use assumptions for environment-dependent tests

458

assume(System.getProperty("env") == "integration", "Integration tests only")

459

460

// Use cancellation for unavailable resources

461

if (!externalServiceAvailable) {

462

cancel("External service unavailable")

463

}

464

```

465

466

### Batch Assertions

467

468

```scala

469

// Multiple related assertions with context

470

withClue("User validation failed") {

471

user.name should not be empty

472

user.email should include("@")

473

user.age should be >= 18

474

}

475

```