or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

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

advanced.mddocs/

0

# Advanced Testing Utilities

1

2

ScalaTest provides specialized utilities for complex testing scenarios including bulk collection assertions, pattern matching tests, private method testing, XML comparison, property-based testing integration, and test execution control. These advanced features enable comprehensive testing of sophisticated systems and edge cases.

3

4

## Capabilities

5

6

### Enhanced Assertion Diagrams

7

8

Visual assertion failure reporting that shows expression evaluation trees for better debugging.

9

10

```scala { .api }

11

/**

12

* Enhanced assertion failure reporting with visual diagrams

13

*/

14

trait Diagrams {

15

/**

16

* Enhanced assert with visual failure diagrams showing expression evaluation

17

* @param condition boolean expression to evaluate

18

*/

19

def assert(condition: Boolean): Assertion

20

21

/**

22

* Enhanced assert with clue and visual failure diagrams

23

* @param condition boolean expression to evaluate

24

* @param clue additional context for failures

25

*/

26

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

27

}

28

```

29

30

**Usage Example:**

31

32

```scala

33

import org.scalatest.funsuite.AnyFunSuite

34

import org.scalatest.matchers.should.Matchers

35

import org.scalatest.diagrams.Diagrams

36

37

class DiagramExampleSpec extends AnyFunSuite with Matchers with Diagrams {

38

39

test("enhanced assertion failure reporting") {

40

val users = List(

41

User("Alice", 25),

42

User("Bob", 30),

43

User("Charlie", 35)

44

)

45

46

// When this fails, diagrams show the evaluation tree

47

assert(users.filter(_.age > 40).nonEmpty)

48

// Shows: users.filter(_.age > 40).nonEmpty was false

49

// users.filter(_.age > 40) was List()

50

// users was List(User("Alice", 25), User("Bob", 30), User("Charlie", 35))

51

}

52

53

test("complex expression diagrams") {

54

val x = 5

55

val y = 10

56

val threshold = 20

57

58

// Enhanced failure reporting shows each step

59

assert((x * 2) + (y / 2) > threshold)

60

// Shows: (x * 2) + (y / 2) > threshold was false

61

// (x * 2) + (y / 2) was 15

62

// (x * 2) was 10, (y / 2) was 5

63

// x was 5, y was 10, threshold was 20

64

}

65

}

66

```

67

68

### Inspectors for Bulk Assertions

69

70

Apply assertions to every element in collections with detailed failure reporting.

71

72

```scala { .api }

73

/**

74

* Bulk assertion utilities for collections

75

*/

76

trait Inspectors {

77

/**

78

* Assert that all elements in collection satisfy the assertion

79

* @param xs the collection to inspect

80

* @param fun assertion applied to each element

81

*/

82

def forAll[E](xs: scala.collection.GenTraversable[E])(fun: E => Unit): Unit

83

84

/**

85

* Assert that at least minimum number of elements satisfy assertion

86

* @param min minimum number of elements that must satisfy assertion

87

* @param xs the collection to inspect

88

* @param fun assertion applied to each element

89

*/

90

def forAtLeast[E](min: Int, xs: scala.collection.GenTraversable[E])(fun: E => Unit): Unit

91

92

/**

93

* Assert that at most maximum number of elements satisfy assertion

94

* @param max maximum number of elements that can satisfy assertion

95

* @param xs the collection to inspect

96

* @param fun assertion applied to each element

97

*/

98

def forAtMost[E](max: Int, xs: scala.collection.GenTraversable[E])(fun: E => Unit): Unit

99

100

/**

101

* Assert that between min and max elements (inclusive) satisfy assertion

102

* @param from minimum number of elements (inclusive)

103

* @param upTo maximum number of elements (inclusive)

104

* @param xs the collection to inspect

105

* @param fun assertion applied to each element

106

*/

107

def forBetween[E](from: Int, upTo: Int, xs: scala.collection.GenTraversable[E])(fun: E => Unit): Unit

108

109

/**

110

* Assert that exactly the specified number of elements satisfy assertion

111

* @param num exact number of elements that must satisfy assertion

112

* @param xs the collection to inspect

113

* @param fun assertion applied to each element

114

*/

115

def forExactly[E](num: Int, xs: scala.collection.GenTraversable[E])(fun: E => Unit): Unit

116

117

/**

118

* Assert that every element in collection satisfies assertion (synonym for forAll)

119

* @param xs the collection to inspect

120

* @param fun assertion applied to each element

121

*/

122

def forEvery[E](xs: scala.collection.GenTraversable[E])(fun: E => Unit): Unit

123

}

124

```

125

126

**Usage Examples:**

127

128

```scala

129

import org.scalatest.funsuite.AnyFunSuite

130

import org.scalatest.matchers.should.Matchers

131

import org.scalatest.Inspectors

132

133

class InspectorExampleSpec extends AnyFunSuite with Matchers with Inspectors {

134

135

test("all users should have valid data") {

136

val users = List(

137

User("Alice", 25, "alice@example.com"),

138

User("Bob", 30, "bob@example.com"),

139

User("Charlie", 35, "charlie@example.com")

140

)

141

142

forAll(users) { user =>

143

user.name should not be empty

144

user.age should be > 0

145

user.email should include("@")

146

}

147

}

148

149

test("at least half of scores should be passing") {

150

val scores = List(85, 92, 67, 78, 95, 88, 72)

151

val passingThreshold = 70

152

153

forAtLeast(scores.length / 2, scores) { score =>

154

score should be >= passingThreshold

155

}

156

}

157

158

test("at most two items should be expensive") {

159

val prices = List(10.99, 250.00, 15.50, 300.00, 25.00, 8.75)

160

val expensiveThreshold = 200.00

161

162

forAtMost(2, prices) { price =>

163

price should be > expensiveThreshold

164

}

165

}

166

167

test("between 2 and 4 words should be capitalized") {

168

val words = List("Hello", "world", "This", "Is", "a", "Test")

169

170

forBetween(2, 4, words) { word =>

171

word.head.isUpper should be(true)

172

}

173

}

174

175

test("exactly one user should be admin") {

176

val users = List(

177

User("Alice", Role.USER),

178

User("Bob", Role.ADMIN),

179

User("Charlie", Role.USER)

180

)

181

182

forExactly(1, users) { user =>

183

user.role should equal(Role.ADMIN)

184

}

185

}

186

187

test("detailed failure reporting") {

188

val numbers = List(1, 2, 3, 4, 5, 6)

189

190

// This will fail and show exactly which elements failed

191

forAll(numbers) { num =>

192

num should be < 5 // Will fail for 5 and 6

193

}

194

}

195

}

196

```

197

198

### Inside Pattern Matching

199

200

Use pattern matching in assertions with detailed failure reporting.

201

202

```scala { .api }

203

/**

204

* Pattern matching assertion utilities

205

*/

206

trait Inside {

207

/**

208

* Apply pattern matching assertion to a value

209

* @param value the value to pattern match against

210

* @param pf partial function containing pattern and assertions

211

*/

212

def inside[T](value: T)(pf: PartialFunction[T, Unit]): Unit

213

}

214

```

215

216

**Usage Examples:**

217

218

```scala

219

import org.scalatest.funsuite.AnyFunSuite

220

import org.scalatest.matchers.should.Matchers

221

import org.scalatest.Inside

222

223

class InsideExampleSpec extends AnyFunSuite with Matchers with Inside {

224

225

test("pattern matching on case classes") {

226

val response = ApiResponse(200, "Success", Some(UserData("Alice", 25)))

227

228

inside(response) {

229

case ApiResponse(status, message, Some(userData)) =>

230

status should equal(200)

231

message should equal("Success")

232

userData.name should equal("Alice")

233

userData.age should be > 18

234

}

235

}

236

237

test("pattern matching on collections") {

238

val numbers = List(1, 2, 3, 4, 5)

239

240

inside(numbers) {

241

case head :: second :: tail =>

242

head should equal(1)

243

second should equal(2)

244

tail should have length 3

245

tail should contain allOf(3, 4, 5)

246

}

247

}

248

249

test("pattern matching on nested structures") {

250

val json = JsonObject(Map(

251

"user" -> JsonObject(Map(

252

"name" -> JsonString("Alice"),

253

"age" -> JsonNumber(25)

254

)),

255

"status" -> JsonString("active")

256

))

257

258

inside(json) {

259

case JsonObject(fields) =>

260

inside(fields("user")) {

261

case JsonObject(userFields) =>

262

inside(userFields("name")) {

263

case JsonString(name) => name should equal("Alice")

264

}

265

inside(userFields("age")) {

266

case JsonNumber(age) => age should equal(25)

267

}

268

}

269

inside(fields("status")) {

270

case JsonString(status) => status should equal("active")

271

}

272

}

273

}

274

275

test("pattern matching with guards") {

276

val event = UserEvent("login", timestamp = System.currentTimeMillis())

277

278

inside(event) {

279

case UserEvent(eventType, timestamp) if timestamp > 0 =>

280

eventType should equal("login")

281

timestamp should be > 0L

282

// Additional assertions based on successful pattern match

283

}

284

}

285

}

286

```

287

288

### Checkpoints for Multiple Assertions

289

290

Create multiple assertion checkpoints that all must pass, with detailed reporting of which ones failed.

291

292

```scala { .api }

293

/**

294

* Multiple assertion checkpoint utilities

295

*/

296

trait Checkpoints {

297

/**

298

* Create a checkpoint with a name

299

* @param name descriptive name for the checkpoint

300

*/

301

def checkpoint(name: String): Checkpoint

302

303

/**

304

* Individual checkpoint that can be used in assertions

305

*/

306

final class Checkpoint(name: String) {

307

/**

308

* Apply assertion to this checkpoint

309

* @param assertion the assertion to apply

310

*/

311

def apply(assertion: => Unit): Unit

312

}

313

}

314

```

315

316

**Usage Examples:**

317

318

```scala

319

import org.scalatest.funsuite.AnyFunSuite

320

import org.scalatest.matchers.should.Matchers

321

import org.scalatest.Checkpoints

322

323

class CheckpointExampleSpec extends AnyFunSuite with Matchers with Checkpoints {

324

325

test("user validation with multiple checkpoints") {

326

val user = User("Alice", 25, "alice@example.com", isActive = true)

327

328

val nameCheck = checkpoint("name validation")

329

val ageCheck = checkpoint("age validation")

330

val emailCheck = checkpoint("email validation")

331

val statusCheck = checkpoint("status validation")

332

333

nameCheck {

334

user.name should not be empty

335

user.name should have length (be >= 2 and be <= 50)

336

}

337

338

ageCheck {

339

user.age should be >= 18

340

user.age should be <= 120

341

}

342

343

emailCheck {

344

user.email should include("@")

345

user.email should include(".")

346

user.email should not startWith "@"

347

}

348

349

statusCheck {

350

user.isActive should be(true)

351

}

352

// If any checkpoint fails, all checkpoint results are reported

353

}

354

355

test("API response validation with checkpoints") {

356

val response = makeApiCall("/users/123")

357

358

val statusCheck = checkpoint("HTTP status")

359

val headersCheck = checkpoint("response headers")

360

val bodyCheck = checkpoint("response body")

361

362

statusCheck {

363

response.status should equal(200)

364

}

365

366

headersCheck {

367

response.headers should contain key "Content-Type"

368

response.headers("Content-Type") should include("application/json")

369

}

370

371

bodyCheck {

372

val user = parseUser(response.body)

373

user.id should equal(123)

374

user.name should not be empty

375

}

376

}

377

}

378

```

379

380

### Private Method Testing

381

382

Test private methods using reflection-based invocation.

383

384

```scala { .api }

385

/**

386

* Private method testing utilities

387

*/

388

trait PrivateMethodTester {

389

/**

390

* Create a private method invocation

391

* @param methodName the name of the private method (as Symbol)

392

* @return PrivateMethod instance for invocation

393

*/

394

def PrivateMethod[T](methodName: Symbol): PrivateMethod[T]

395

396

/**

397

* Private method wrapper for invocation

398

*/

399

final class PrivateMethod[T](methodName: Symbol) {

400

/**

401

* Invoke the private method

402

* @param target the object containing the private method

403

* @param args arguments to pass to the method

404

* @return result of the method invocation

405

*/

406

def invokeOn(target: AnyRef, args: Any*): T

407

}

408

409

/**

410

* Alternative syntax for private method invocation

411

* @param target the object containing the private method

412

* @param methodName the private method name (as Symbol)

413

* @param args arguments to pass to the method

414

* @return result of the method invocation

415

*/

416

def invokePrivate[T](target: AnyRef, methodName: Symbol, args: Any*): T

417

}

418

```

419

420

**Usage Examples:**

421

422

```scala

423

import org.scalatest.funsuite.AnyFunSuite

424

import org.scalatest.matchers.should.Matchers

425

import org.scalatest.PrivateMethodTester

426

427

class Calculator {

428

def add(a: Int, b: Int): Int = a + b

429

430

private def validateInput(value: Int): Boolean = value >= 0

431

432

private def complexCalculation(x: Double, y: Double): Double = {

433

val intermediate = x * 2 + y / 3

434

math.sqrt(intermediate)

435

}

436

}

437

438

class PrivateMethodTestSpec extends AnyFunSuite with Matchers with PrivateMethodTester {

439

440

test("testing private validation method") {

441

val calculator = new Calculator()

442

val validateInput = PrivateMethod[Boolean](Symbol("validateInput"))

443

444

// Test private method with valid input

445

val result1 = validateInput.invokeOn(calculator, 5)

446

result1 should be(true)

447

448

// Test private method with invalid input

449

val result2 = validateInput.invokeOn(calculator, -1)

450

result2 should be(false)

451

}

452

453

test("testing private calculation method") {

454

val calculator = new Calculator()

455

val complexCalculation = PrivateMethod[Double](Symbol("complexCalculation"))

456

457

val result = complexCalculation.invokeOn(calculator, 4.0, 6.0)

458

result should be(3.0 +- 0.001) // sqrt(4*2 + 6/3) = sqrt(10) ≈ 3.16

459

}

460

461

test("alternative syntax for private method testing") {

462

val calculator = new Calculator()

463

464

// Using invokePrivate directly

465

val isValid = invokePrivate[Boolean](calculator, Symbol("validateInput"), 10)

466

isValid should be(true)

467

468

val calculation = invokePrivate[Double](calculator, Symbol("complexCalculation"), 1.0, 3.0)

469

calculation should be > 0.0

470

}

471

472

test("private method with multiple parameters") {

473

class StringProcessor {

474

private def processStrings(s1: String, s2: String, delimiter: String): String = {

475

s"$s1$delimiter$s2"

476

}

477

}

478

479

val processor = new StringProcessor()

480

val processStrings = PrivateMethod[String](Symbol("processStrings"))

481

482

val result = processStrings.invokeOn(processor, "Hello", "World", " - ")

483

result should equal("Hello - World")

484

}

485

}

486

```

487

488

### XML Testing Utilities

489

490

Specialized utilities for testing XML content with normalization and comparison.

491

492

```scala { .api }

493

/**

494

* XML testing utilities with normalization

495

*/

496

trait StreamlinedXml {

497

/**

498

* Normalize XML for comparison (whitespace, formatting)

499

*/

500

implicit def convertToXmlWrapper(xml: scala.xml.Node): XmlWrapper

501

502

final class XmlWrapper(xml: scala.xml.Node) {

503

/**

504

* Compare XML content ignoring formatting differences

505

*/

506

def ===(other: scala.xml.Node): Boolean

507

}

508

}

509

510

/**

511

* XML equality with normalization

512

*/

513

trait StreamlinedXmlEquality {

514

// Enables normalized XML comparison in assertions

515

}

516

517

/**

518

* XML normalization methods

519

*/

520

trait StreamlinedXmlNormMethods {

521

/**

522

* Normalize XML node for comparison

523

* @param node the XML node to normalize

524

* @return normalized XML node

525

*/

526

def normalizeXml(node: scala.xml.Node): scala.xml.Node

527

}

528

```

529

530

**Usage Examples:**

531

532

```scala

533

import org.scalatest.funsuite.AnyFunSuite

534

import org.scalatest.matchers.should.Matchers

535

import org.scalatest.StreamlinedXml

536

import scala.xml._

537

538

class XmlTestingSpec extends AnyFunSuite with Matchers with StreamlinedXml {

539

540

test("XML comparison ignoring formatting") {

541

val xml1 = <user><name>Alice</name><age>25</age></user>

542

val xml2 =

543

<user>

544

<name>Alice</name>

545

<age>25</age>

546

</user>

547

548

// Different formatting, same content

549

xml1 should ===(xml2)

550

}

551

552

test("XML content validation") {

553

val userXml = <user id="123"><name>Bob</name><email>bob@example.com</email></user>

554

555

// Test XML structure and content

556

(userXml \ "@id").text should equal("123")

557

(userXml \ "name").text should equal("Bob")

558

(userXml \ "email").text should include("@")

559

}

560

561

test("complex XML comparison") {

562

val expected =

563

<response>

564

<status>success</status>

565

<data>

566

<users>

567

<user id="1">Alice</user>

568

<user id="2">Bob</user>

569

</users>

570

</data>

571

</response>

572

573

val actual = generateXmlResponse()

574

575

actual should ===(expected)

576

577

// Also test specific parts

578

(actual \ "status").text should equal("success")

579

(actual \\ "user").length should equal(2)

580

}

581

582

test("XML with attributes and namespaces") {

583

val soapEnvelope =

584

<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">

585

<soap:Body>

586

<getUserResponse xmlns="http://example.com/users">

587

<user id="123" active="true">

588

<name>Charlie</name>

589

</user>

590

</getUserResponse>

591

</soap:Body>

592

</soap:Envelope>

593

594

// Test namespace handling

595

(soapEnvelope \ "Body" \ "getUserResponse" \ "user" \ "@id").text should equal("123")

596

(soapEnvelope \ "Body" \ "getUserResponse" \ "user" \ "@active").text should equal("true")

597

}

598

}

599

```

600

601

### Test Execution Control

602

603

Control how tests are executed including parallel execution, ordering, and failure handling.

604

605

```scala { .api }

606

/**

607

* Execute tests in parallel within the suite

608

*/

609

trait ParallelTestExecution extends OneInstancePerTest {

610

// Tests in this suite run in parallel

611

}

612

613

/**

614

* Randomize test execution order

615

*/

616

trait RandomTestOrder extends Suite {

617

// Tests execute in random order each run

618

}

619

620

/**

621

* Force sequential test execution (override parallel settings)

622

*/

623

trait Sequential extends Suite {

624

// Tests execute sequentially even if parallel execution is configured

625

}

626

627

/**

628

* Stop test suite execution on first failure

629

*/

630

trait StopOnFailure extends Suite {

631

// Suite stops executing tests after first failure

632

}

633

634

/**

635

* Cancel remaining tests after first failure

636

*/

637

trait CancelAfterFailure extends Suite {

638

// Remaining tests are cancelled (not failed) after first failure

639

}

640

641

/**

642

* Execute tests before nested suites

643

*/

644

trait TestsBeforeNestedSuites extends Suite {

645

// Tests in this suite run before any nested suites

646

}

647

```

648

649

**Usage Examples:**

650

651

```scala

652

import org.scalatest.funsuite.AnyFunSuite

653

import org.scalatest.matchers.should.Matchers

654

import org.scalatest.{ParallelTestExecution, RandomTestOrder, StopOnFailure}

655

656

class ParallelExecutionSpec extends AnyFunSuite with Matchers with ParallelTestExecution {

657

658

test("parallel test 1") {

659

Thread.sleep(100)

660

1 + 1 should equal(2)

661

}

662

663

test("parallel test 2") {

664

Thread.sleep(50)

665

2 + 2 should equal(4)

666

}

667

668

test("parallel test 3") {

669

Thread.sleep(75)

670

3 + 3 should equal(6)

671

}

672

// These tests run concurrently

673

}

674

675

class RandomOrderSpec extends AnyFunSuite with Matchers with RandomTestOrder {

676

677

test("test A") {

678

println("Executing test A")

679

succeed

680

}

681

682

test("test B") {

683

println("Executing test B")

684

succeed

685

}

686

687

test("test C") {

688

println("Executing test C")

689

succeed

690

}

691

// Execution order varies between runs

692

}

693

694

class FailFastSpec extends AnyFunSuite with Matchers with StopOnFailure {

695

696

test("this test passes") {

697

1 should equal(1)

698

}

699

700

test("this test fails") {

701

fail("Intentional failure")

702

}

703

704

test("this test would be skipped") {

705

// This test won't execute due to StopOnFailure

706

2 should equal(2)

707

}

708

}

709

```

710

711

### Test Communication and Documentation

712

713

Add runtime information, alerts, and documentation to tests.

714

715

```scala { .api }

716

/**

717

* Provide runtime information during test execution

718

*/

719

trait Informing {

720

/**

721

* Add information to test output

722

* @param informer the informer instance

723

*/

724

protected def info: Informer

725

}

726

727

trait Informer {

728

/**

729

* Provide information during test execution

730

* @param message information message

731

*/

732

def apply(message: String): Unit

733

}

734

735

/**

736

* Send alert messages during test execution

737

*/

738

trait Alerting {

739

protected def alert: Alerter

740

}

741

742

trait Alerter {

743

def apply(message: String): Unit

744

}

745

746

/**

747

* Add documentation to tests

748

*/

749

trait Documenting {

750

protected def markup: Documenter

751

}

752

753

trait Documenter {

754

def apply(message: String): Unit

755

}

756

757

/**

758

* BDD-style test documentation

759

*/

760

trait GivenWhenThen {

761

/**

762

* Document test preconditions

763

* @param message description of given conditions

764

*/

765

def Given(message: String): Unit

766

767

/**

768

* Document test actions

769

* @param message description of actions taken

770

*/

771

def When(message: String): Unit

772

773

/**

774

* Document expected outcomes

775

* @param message description of expected results

776

*/

777

def Then(message: String): Unit

778

779

/**

780

* Document additional conditions or actions

781

* @param message description of additional context

782

*/

783

def And(message: String): Unit

784

}

785

```

786

787

**Usage Examples:**

788

789

```scala

790

import org.scalatest.funsuite.AnyFunSuite

791

import org.scalatest.matchers.should.Matchers

792

import org.scalatest.GivenWhenThen

793

794

class DocumentedTestSpec extends AnyFunSuite with Matchers with GivenWhenThen {

795

796

test("user registration process") {

797

Given("a new user wants to register")

798

val userData = UserRegistrationData("Alice", "alice@example.com", "password123")

799

800

And("the email is not already taken")

801

val userService = new UserService()

802

userService.isEmailAvailable(userData.email) should be(true)

803

804

When("the user submits registration")

805

val result = userService.registerUser(userData)

806

807

Then("the user should be created successfully")

808

result.isSuccess should be(true)

809

result.user.name should equal("Alice")

810

811

And("the user should receive a confirmation email")

812

val emailService = new EmailService()

813

emailService.wasConfirmationSent(result.user.email) should be(true)

814

815

info("Registration completed with user ID: " + result.user.id)

816

}

817

818

test("shopping cart workflow with detailed documentation") {

819

Given("an empty shopping cart")

820

val cart = new ShoppingCart()

821

cart.items should be(empty)

822

823

When("items are added to the cart")

824

val book = Product("Scala Programming", 39.99)

825

val pen = Product("Blue Pen", 2.50)

826

827

cart.addItem(book)

828

cart.addItem(pen)

829

830

Then("the cart should contain the items")

831

cart.items should have size 2

832

cart.items should contain allOf(book, pen)

833

834

And("the total should be calculated correctly")

835

cart.total should equal(42.49)

836

837

info(s"Cart total: ${cart.total}")

838

markup("This test demonstrates the basic shopping cart functionality")

839

}

840

}

841

```

842

843

## Common Advanced Patterns

844

845

### Comprehensive Collection Validation

846

847

```scala

848

test("validate entire user collection") {

849

val users = loadUsers()

850

851

forAll(users) { user =>

852

inside(user) {

853

case User(name, age, email, profile) =>

854

name should not be empty

855

age should (be >= 18 and be <= 120)

856

email should fullyMatch(emailRegex)

857

858

inside(profile) {

859

case Some(UserProfile(bio, location)) =>

860

bio should have length (be <= 500)

861

location should not be empty

862

case None => // OK for profile to be empty

863

}

864

}

865

}

866

}

867

```

868

869

### Complex Data Structure Testing

870

871

```scala

872

test("validate API response structure") {

873

val response = callApi("/users/123")

874

875

val statusCheck = checkpoint("status validation")

876

val dataCheck = checkpoint("data validation")

877

val metaCheck = checkpoint("metadata validation")

878

879

statusCheck {

880

response.status should be(200)

881

}

882

883

inside(response.body) {

884

case ApiResponse(data, metadata, links) =>

885

dataCheck {

886

inside(data) {

887

case UserData(id, name, email, preferences) =>

888

id should equal(123)

889

name should not be empty

890

email should include("@")

891

}

892

}

893

894

metaCheck {

895

metadata.version should equal("1.0")

896

metadata.timestamp should be > 0L

897

}

898

}

899

}

900

```

901

902

### Private Method Integration Testing

903

904

```scala

905

test("internal processing pipeline") {

906

val processor = new DataProcessor()

907

908

// Test individual private methods

909

val validateData = PrivateMethod[Boolean](Symbol("validateData"))

910

val transformData = PrivateMethod[ProcessedData](Symbol("transformData"))

911

val persistData = PrivateMethod[String](Symbol("persistData"))

912

913

val rawData = RawData("test data")

914

915

validateData.invokeOn(processor, rawData) should be(true)

916

917

val transformed = transformData.invokeOn(processor, rawData)

918

transformed.isValid should be(true)

919

920

val id = persistData.invokeOn(processor, transformed)

921

id should not be empty

922

}

923

```