or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

annotations.mdassertions.mdassumptions.mdcategories.mdindex.mdmatchers.mdrules.mdstandard-runners.mdtest-runners.mdtheories.md

rules.mddocs/

0

# Rules

1

2

Rules provide a way to add reusable behavior around test execution. They can be applied to individual test methods (`@Rule`) or entire test classes (`@ClassRule`). Rules are more flexible and composable than inheritance-based approaches.

3

4

## Capabilities

5

6

### TestRule Interface

7

8

The core interface for implementing custom rules. Rules wrap test execution with custom behavior.

9

10

```java { .api }

11

/**

12

* Interface for test rules

13

* A rule wraps test execution with custom behavior

14

*/

15

public interface TestRule {

16

/**

17

* Modifies the Statement that executes a test

18

* @param base - The Statement to be modified

19

* @param description - Description of the test

20

* @return Modified Statement

21

*/

22

Statement apply(Statement base, Description description);

23

}

24

```

25

26

**Usage Examples:**

27

28

```java

29

import org.junit.rules.TestRule;

30

import org.junit.runner.Description;

31

import org.junit.runners.model.Statement;

32

33

public class LoggingRule implements TestRule {

34

@Override

35

public Statement apply(Statement base, Description description) {

36

return new Statement() {

37

@Override

38

public void evaluate() throws Throwable {

39

System.out.println("Starting: " + description.getMethodName());

40

try {

41

base.evaluate();

42

System.out.println("Passed: " + description.getMethodName());

43

} catch (Throwable t) {

44

System.out.println("Failed: " + description.getMethodName());

45

throw t;

46

}

47

}

48

};

49

}

50

}

51

52

// Usage

53

public class MyTest {

54

@Rule

55

public TestRule loggingRule = new LoggingRule();

56

57

@Test

58

public void testSomething() {

59

// Logging happens automatically

60

assertTrue(true);

61

}

62

}

63

```

64

65

### TemporaryFolder

66

67

Creates temporary files and folders that are automatically deleted after the test. Useful for tests that need file system access.

68

69

```java { .api }

70

/**

71

* Rule for creating temporary files and folders

72

* Automatically deleted after test completion

73

*/

74

public class TemporaryFolder extends ExternalResource {

75

/**

76

* Creates a TemporaryFolder using default temp directory

77

*/

78

public TemporaryFolder();

79

80

/**

81

* Creates a TemporaryFolder in specified parent folder

82

* @param parentFolder - Parent directory for temp folder

83

*/

84

public TemporaryFolder(File parentFolder);

85

86

/**

87

* Get the root temporary folder

88

* @return Root folder (created lazily)

89

*/

90

public File getRoot();

91

92

/**

93

* Create a new temporary file with random name

94

* @return Created file

95

* @throws IOException if file cannot be created

96

*/

97

public File newFile() throws IOException;

98

99

/**

100

* Create a new temporary file with specified name

101

* @param filename - Name for the file

102

* @return Created file

103

* @throws IOException if file cannot be created

104

*/

105

public File newFile(String filename) throws IOException;

106

107

/**

108

* Create a new temporary folder with random name

109

* @return Created folder

110

* @throws IOException if folder cannot be created

111

*/

112

public File newFolder() throws IOException;

113

114

/**

115

* Create a new temporary folder with specified name

116

* @param folderName - Name for the folder

117

* @return Created folder

118

* @throws IOException if folder cannot be created

119

*/

120

public File newFolder(String folderName) throws IOException;

121

122

/**

123

* Create a new temporary folder with path segments

124

* @param folderNames - Path segments for nested folders

125

* @return Created folder

126

* @throws IOException if folder cannot be created

127

*/

128

public File newFolder(String... folderNames) throws IOException;

129

130

/**

131

* Delete all files and folders

132

*/

133

public void delete();

134

135

/**

136

* Builder for configuring TemporaryFolder

137

*/

138

public static class Builder {

139

public Builder parentFolder(File parentFolder);

140

public Builder assureDeletion();

141

public TemporaryFolder build();

142

}

143

144

public static Builder builder();

145

}

146

```

147

148

**Usage Examples:**

149

150

```java

151

import org.junit.Rule;

152

import org.junit.Test;

153

import org.junit.rules.TemporaryFolder;

154

import java.io.*;

155

import static org.junit.Assert.*;

156

157

public class FileTest {

158

@Rule

159

public TemporaryFolder folder = new TemporaryFolder();

160

161

@Test

162

public void testFileCreation() throws IOException {

163

File file = folder.newFile("test.txt");

164

assertTrue(file.exists());

165

// File automatically deleted after test

166

}

167

168

@Test

169

public void testFileWrite() throws IOException {

170

File file = folder.newFile("data.txt");

171

FileWriter writer = new FileWriter(file);

172

writer.write("Hello, World!");

173

writer.close();

174

175

BufferedReader reader = new BufferedReader(new FileReader(file));

176

assertEquals("Hello, World!", reader.readLine());

177

reader.close();

178

}

179

180

@Test

181

public void testFolderCreation() throws IOException {

182

File subFolder = folder.newFolder("subfolder");

183

File nestedFile = new File(subFolder, "nested.txt");

184

nestedFile.createNewFile();

185

assertTrue(nestedFile.exists());

186

}

187

188

@Test

189

public void testNestedFolders() throws IOException {

190

File nested = folder.newFolder("level1", "level2", "level3");

191

assertTrue(nested.exists());

192

assertTrue(nested.isDirectory());

193

}

194

}

195

196

// Using builder

197

public class ConfiguredFolderTest {

198

@Rule

199

public TemporaryFolder folder = TemporaryFolder.builder()

200

.parentFolder(new File("/tmp"))

201

.assureDeletion()

202

.build();

203

}

204

```

205

206

### ExpectedException

207

208

**DEPRECATED since JUnit 4.13** - Use `Assert.assertThrows()` instead.

209

210

Verifies that code throws expected exceptions with specific properties. More flexible than `@Test(expected=...)`.

211

212

```java { .api }

213

/**

214

* Rule for verifying expected exceptions

215

* Provides detailed exception matching

216

*

217

* @deprecated Since 4.13 - Use Assert.assertThrows(Class, ThrowingRunnable) instead

218

*/

219

@Deprecated

220

public class ExpectedException implements TestRule {

221

/**

222

* Create an ExpectedException rule

223

* @return New ExpectedException instance

224

* @deprecated Since 4.13 - Use Assert.assertThrows() instead

225

*/

226

@Deprecated

227

public static ExpectedException none();

228

229

/**

230

* Expect exception of specific type

231

* @param type - Expected exception class

232

*/

233

public void expect(Class<? extends Throwable> type);

234

235

/**

236

* Expect exception matching a matcher

237

* @param matcher - Hamcrest matcher for exception

238

*/

239

public void expect(Matcher<?> matcher);

240

241

/**

242

* Expect exception message containing specific text

243

* @param substring - Expected substring in message

244

*/

245

public void expectMessage(String substring);

246

247

/**

248

* Expect exception message matching a matcher

249

* @param matcher - Hamcrest matcher for message

250

*/

251

public void expectMessage(Matcher<String> matcher);

252

253

/**

254

* Expect exception cause matching a matcher

255

* @param expectedCause - Matcher for cause

256

*/

257

public void expectCause(Matcher<? extends Throwable> expectedCause);

258

259

/**

260

* Check if any exception is expected

261

* @return true if exception expected

262

*/

263

public boolean isAnyExceptionExpected();

264

265

/**

266

* Configure to handle AssertionErrors as exceptions

267

* @return This instance for chaining

268

*/

269

public ExpectedException handleAssertionErrors();

270

271

/**

272

* Configure to handle AssumptionViolatedExceptions

273

* @return This instance for chaining

274

*/

275

public ExpectedException handleAssumptionViolatedExceptions();

276

277

/**

278

* Configure custom message for missing exception

279

* @param message - Custom message

280

* @return This instance for chaining

281

*/

282

public ExpectedException reportMissingExceptionWithMessage(String message);

283

}

284

```

285

286

**Usage Examples:**

287

288

```java

289

import org.junit.Rule;

290

import org.junit.Test;

291

import org.junit.rules.ExpectedException;

292

import static org.hamcrest.CoreMatchers.*;

293

294

public class ExceptionTest {

295

@Rule

296

public ExpectedException thrown = ExpectedException.none();

297

298

@Test

299

public void testExceptionType() {

300

thrown.expect(IllegalArgumentException.class);

301

throw new IllegalArgumentException("Invalid argument");

302

}

303

304

@Test

305

public void testExceptionMessage() {

306

thrown.expect(NullPointerException.class);

307

thrown.expectMessage("Cannot be null");

308

processNull(null);

309

}

310

311

@Test

312

public void testExceptionMessagePattern() {

313

thrown.expect(IllegalStateException.class);

314

thrown.expectMessage(containsString("invalid state"));

315

performInvalidOperation();

316

}

317

318

@Test

319

public void testExceptionCause() {

320

thrown.expect(RuntimeException.class);

321

thrown.expectCause(isA(IOException.class));

322

throw new RuntimeException("Wrapped", new IOException("IO error"));

323

}

324

325

@Test

326

public void testMultipleConditions() {

327

thrown.expect(IllegalArgumentException.class);

328

thrown.expectMessage(startsWith("Invalid"));

329

thrown.expectMessage(containsString("parameter"));

330

validateParameter(-1);

331

}

332

}

333

```

334

335

### Timeout

336

337

Applies a timeout to all test methods in a class. Test fails if it runs longer than specified time.

338

339

```java { .api }

340

/**

341

* Rule for enforcing test timeouts

342

*/

343

public class Timeout implements TestRule {

344

/**

345

* Create timeout in milliseconds

346

* @param millis - Timeout in milliseconds

347

* @return Timeout rule

348

*/

349

public static Timeout millis(long millis);

350

351

/**

352

* Create timeout in seconds

353

* @param seconds - Timeout in seconds

354

* @return Timeout rule

355

*/

356

public static Timeout seconds(long seconds);

357

358

/**

359

* Get builder for configuring timeout

360

* @return Builder instance

361

*/

362

public static Builder builder();

363

364

/**

365

* Builder for Timeout configuration

366

*/

367

public static class Builder {

368

/**

369

* Set timeout duration

370

* @param timeout - Timeout value

371

* @param unit - Time unit

372

* @return This builder

373

*/

374

public Builder withTimeout(long timeout, TimeUnit unit);

375

376

/**

377

* Enable looking for stuck threads

378

* @param enable - Whether to look for stuck threads

379

* @return This builder

380

*/

381

public Builder withLookingForStuckThread(boolean enable);

382

383

/**

384

* Build the Timeout rule

385

* @return Configured Timeout

386

*/

387

public Timeout build();

388

}

389

}

390

```

391

392

**Usage Examples:**

393

394

```java

395

import org.junit.Rule;

396

import org.junit.Test;

397

import org.junit.rules.Timeout;

398

import java.util.concurrent.TimeUnit;

399

400

public class TimeoutTest {

401

@Rule

402

public Timeout globalTimeout = Timeout.seconds(10);

403

404

@Test

405

public void testFastOperation() {

406

// Must complete within 10 seconds

407

performQuickOperation();

408

}

409

410

@Test

411

public void testAnotherOperation() {

412

// Also must complete within 10 seconds

413

performOperation();

414

}

415

}

416

417

// Using builder

418

public class ConfiguredTimeoutTest {

419

@Rule

420

public Timeout timeout = Timeout.builder()

421

.withTimeout(5, TimeUnit.SECONDS)

422

.withLookingForStuckThread(true)

423

.build();

424

425

@Test

426

public void testWithStuckThreadDetection() {

427

performOperation();

428

}

429

}

430

431

// Milliseconds timeout

432

public class MillisTimeoutTest {

433

@Rule

434

public Timeout timeout = Timeout.millis(500);

435

436

@Test

437

public void testVeryFastOperation() {

438

// Must complete within 500ms

439

quickOperation();

440

}

441

}

442

```

443

444

### TestName

445

446

Provides access to the name of the currently executing test method. Useful for debugging and logging.

447

448

```java { .api }

449

/**

450

* Rule for accessing current test method name

451

*/

452

public class TestName extends TestWatcher {

453

/**

454

* Get the name of the current test method

455

* @return Test method name

456

*/

457

public String getMethodName();

458

}

459

```

460

461

**Usage Examples:**

462

463

```java

464

import org.junit.Rule;

465

import org.junit.Test;

466

import org.junit.rules.TestName;

467

import static org.junit.Assert.*;

468

469

public class NamedTest {

470

@Rule

471

public TestName testName = new TestName();

472

473

@Test

474

public void testA() {

475

assertEquals("testA", testName.getMethodName());

476

System.out.println("Running: " + testName.getMethodName());

477

}

478

479

@Test

480

public void testB() {

481

assertEquals("testB", testName.getMethodName());

482

}

483

484

@Test

485

public void testWithLogging() {

486

String currentTest = testName.getMethodName();

487

log("Starting test: " + currentTest);

488

performOperation();

489

log("Finished test: " + currentTest);

490

}

491

}

492

```

493

494

### ErrorCollector

495

496

Collects multiple errors in a single test, allowing the test to continue after failures. Useful for validating multiple conditions.

497

498

```java { .api }

499

/**

500

* Rule for collecting multiple errors

501

* Test continues after failures and reports all errors at end

502

*/

503

public class ErrorCollector extends Verifier {

504

/**

505

* Add an error

506

* @param error - Throwable to collect

507

*/

508

public void addError(Throwable error);

509

510

/**

511

* Check a condition and collect error if false

512

* @param value - Value to check

513

* @param matcher - Matcher to apply

514

*/

515

public <T> void checkThat(T value, Matcher<T> matcher);

516

517

/**

518

* Check a condition with reason

519

* @param reason - Reason for the check

520

* @param value - Value to check

521

* @param matcher - Matcher to apply

522

*/

523

public <T> void checkThat(String reason, T value, Matcher<T> matcher);

524

525

/**

526

* Call a callable and collect errors

527

* @param callable - Code to execute

528

* @return Result of callable

529

*/

530

public <T> T checkSucceeds(Callable<T> callable);

531

532

/**

533

* Check that runnable throws expected exception

534

* @param expectedThrowable - Expected exception type

535

* @param runnable - Code to execute

536

*/

537

public <T extends Throwable> void checkThrows(

538

Class<T> expectedThrowable,

539

ThrowingRunnable runnable

540

);

541

}

542

```

543

544

**Usage Examples:**

545

546

```java

547

import org.junit.Rule;

548

import org.junit.Test;

549

import org.junit.rules.ErrorCollector;

550

import static org.hamcrest.CoreMatchers.*;

551

552

public class MultipleChecksTest {

553

@Rule

554

public ErrorCollector collector = new ErrorCollector();

555

556

@Test

557

public void testMultipleValues() {

558

// All checks are performed even if some fail

559

collector.checkThat("First check", 1 + 1, is(2));

560

collector.checkThat("Second check", 2 + 2, is(4));

561

collector.checkThat("Third check", 3 + 3, is(6));

562

// If any fail, all failures are reported together

563

}

564

565

@Test

566

public void testTableData() {

567

int[][] table = getTestData();

568

for (int i = 0; i < table.length; i++) {

569

for (int j = 0; j < table[i].length; j++) {

570

collector.checkThat(

571

"Cell [" + i + "][" + j + "]",

572

table[i][j],

573

greaterThan(0)

574

);

575

}

576

}

577

// Reports all failing cells, not just the first one

578

}

579

580

@Test

581

public void testWithCallable() {

582

String result = collector.checkSucceeds(() -> {

583

return performOperation();

584

});

585

assertNotNull(result);

586

}

587

}

588

```

589

590

### ExternalResource

591

592

Base class for rules that set up and tear down external resources. Template for resource management.

593

594

```java { .api }

595

/**

596

* Base class for rules that manage external resources

597

*/

598

public abstract class ExternalResource implements TestRule {

599

/**

600

* Override to set up resource before test

601

*/

602

protected void before() throws Throwable;

603

604

/**

605

* Override to tear down resource after test

606

*/

607

protected void after();

608

}

609

```

610

611

**Usage Examples:**

612

613

```java

614

import org.junit.rules.ExternalResource;

615

import org.junit.Rule;

616

import org.junit.Test;

617

618

public class DatabaseResource extends ExternalResource {

619

private Database database;

620

621

@Override

622

protected void before() throws Throwable {

623

database = new Database();

624

database.connect();

625

database.initialize();

626

}

627

628

@Override

629

protected void after() {

630

if (database != null) {

631

database.disconnect();

632

}

633

}

634

635

public Database getDatabase() {

636

return database;

637

}

638

}

639

640

public class DatabaseTest {

641

@Rule

642

public DatabaseResource dbResource = new DatabaseResource();

643

644

@Test

645

public void testQuery() {

646

Database db = dbResource.getDatabase();

647

Result result = db.query("SELECT * FROM users");

648

assertNotNull(result);

649

}

650

}

651

652

// Server resource example

653

public class ServerResource extends ExternalResource {

654

private TestServer server;

655

private int port;

656

657

public ServerResource(int port) {

658

this.port = port;

659

}

660

661

@Override

662

protected void before() throws Throwable {

663

server = new TestServer(port);

664

server.start();

665

}

666

667

@Override

668

protected void after() {

669

if (server != null) {

670

server.stop();

671

}

672

}

673

674

public String getUrl() {

675

return "http://localhost:" + port;

676

}

677

}

678

```

679

680

### RuleChain

681

682

Chains multiple rules to execute in a specific order. Useful when rules have dependencies.

683

684

```java { .api }

685

/**

686

* Chains multiple rules to execute in order

687

*/

688

public class RuleChain implements TestRule {

689

/**

690

* Create an empty rule chain

691

* @return Empty RuleChain

692

*/

693

public static RuleChain emptyRuleChain();

694

695

/**

696

* Create a rule chain starting with a rule

697

* @param outerRule - First rule in chain

698

* @return RuleChain with the rule

699

*/

700

public static RuleChain outerRule(TestRule outerRule);

701

702

/**

703

* Add a rule to the chain

704

* @param rule - Rule to add

705

* @return This RuleChain

706

*/

707

public RuleChain around(TestRule rule);

708

}

709

```

710

711

**Usage Examples:**

712

713

```java

714

import org.junit.Rule;

715

import org.junit.Test;

716

import org.junit.rules.RuleChain;

717

import org.junit.rules.ExternalResource;

718

import org.junit.rules.TestRule;

719

720

public class ChainedRulesTest {

721

private DatabaseResource database = new DatabaseResource();

722

private ServerResource server = new ServerResource(8080);

723

724

@Rule

725

public TestRule chain = RuleChain

726

.outerRule(database) // First: set up database

727

.around(server); // Then: start server (can use database)

728

729

@Test

730

public void testWithBothResources() {

731

// Both database and server are available

732

makeRequestToServer();

733

}

734

}

735

736

// More complex chain

737

public class ComplexChainTest {

738

@Rule

739

public TestRule chain = RuleChain

740

.outerRule(new LoggingRule())

741

.around(new TimeoutRule())

742

.around(new ResourceRule());

743

744

@Test

745

public void test() {

746

// Rules execute in order: Logging -> Timeout -> Resource

747

// Cleanup happens in reverse: Resource -> Timeout -> Logging

748

}

749

}

750

```

751

752

### TestWatcher

753

754

Observes test execution and provides hooks for test lifecycle events. Base class for monitoring rules.

755

756

```java { .api }

757

/**

758

* Base class for rules that observe test execution

759

*/

760

public abstract class TestWatcher implements TestRule {

761

/**

762

* Called when test succeeds

763

* @param description - Test description

764

*/

765

protected void succeeded(Description description);

766

767

/**

768

* Called when test fails

769

* @param e - Throwable that caused failure

770

* @param description - Test description

771

*/

772

protected void failed(Throwable e, Description description);

773

774

/**

775

* Called when test is skipped

776

* @param e - AssumptionViolatedException

777

* @param description - Test description

778

*/

779

protected void skipped(AssumptionViolatedException e, Description description);

780

781

/**

782

* Called when test is about to start

783

* @param description - Test description

784

*/

785

protected void starting(Description description);

786

787

/**

788

* Called when test finishes (success or failure)

789

* @param description - Test description

790

*/

791

protected void finished(Description description);

792

}

793

```

794

795

**Usage Examples:**

796

797

```java

798

import org.junit.rules.TestWatcher;

799

import org.junit.runner.Description;

800

import org.junit.Rule;

801

import org.junit.Test;

802

803

public class DetailedWatcher extends TestWatcher {

804

@Override

805

protected void starting(Description description) {

806

System.out.println("Starting: " + description.getMethodName());

807

}

808

809

@Override

810

protected void succeeded(Description description) {

811

System.out.println("PASSED: " + description.getMethodName());

812

}

813

814

@Override

815

protected void failed(Throwable e, Description description) {

816

System.out.println("FAILED: " + description.getMethodName());

817

System.out.println("Error: " + e.getMessage());

818

}

819

820

@Override

821

protected void finished(Description description) {

822

System.out.println("Finished: " + description.getMethodName());

823

}

824

}

825

826

public class WatchedTest {

827

@Rule

828

public TestWatcher watcher = new DetailedWatcher();

829

830

@Test

831

public void testSomething() {

832

assertTrue(true);

833

}

834

}

835

836

// Screenshot on failure example

837

public class ScreenshotOnFailure extends TestWatcher {

838

@Override

839

protected void failed(Throwable e, Description description) {

840

String testName = description.getMethodName();

841

takeScreenshot(testName + "_failure.png");

842

}

843

844

private void takeScreenshot(String filename) {

845

// Screenshot logic

846

}

847

}

848

```

849

850

### Stopwatch

851

852

Measures and logs test execution time. Provides hooks for accessing timing information.

853

854

```java { .api }

855

/**

856

* Rule for measuring test execution time

857

*/

858

public class Stopwatch implements TestRule {

859

/**

860

* Get runtime in milliseconds

861

* @param unit - Time unit to convert to

862

* @return Runtime in specified unit

863

*/

864

public long runtime(TimeUnit unit);

865

866

/**

867

* Called when test succeeds

868

* @param nanos - Execution time in nanoseconds

869

* @param description - Test description

870

*/

871

protected void succeeded(long nanos, Description description);

872

873

/**

874

* Called when test fails

875

* @param nanos - Execution time in nanoseconds

876

* @param e - Throwable that caused failure

877

* @param description - Test description

878

*/

879

protected void failed(long nanos, Throwable e, Description description);

880

881

/**

882

* Called when test is skipped

883

* @param nanos - Time until skip

884

* @param e - AssumptionViolatedException

885

* @param description - Test description

886

*/

887

protected void skipped(long nanos, AssumptionViolatedException e, Description description);

888

889

/**

890

* Called when test finishes

891

* @param nanos - Execution time in nanoseconds

892

* @param description - Test description

893

*/

894

protected void finished(long nanos, Description description);

895

}

896

```

897

898

**Usage Examples:**

899

900

```java

901

import org.junit.Rule;

902

import org.junit.Test;

903

import org.junit.rules.Stopwatch;

904

import org.junit.runner.Description;

905

import java.util.concurrent.TimeUnit;

906

907

public class TimingTest {

908

@Rule

909

public Stopwatch stopwatch = new Stopwatch() {

910

@Override

911

protected void succeeded(long nanos, Description description) {

912

long millis = TimeUnit.NANOSECONDS.toMillis(nanos);

913

System.out.println(description.getMethodName() + " succeeded in " + millis + "ms");

914

}

915

916

@Override

917

protected void failed(long nanos, Throwable e, Description description) {

918

long millis = TimeUnit.NANOSECONDS.toMillis(nanos);

919

System.out.println(description.getMethodName() + " failed in " + millis + "ms");

920

}

921

922

@Override

923

protected void finished(long nanos, Description description) {

924

long millis = TimeUnit.NANOSECONDS.toMillis(nanos);

925

System.out.println(description.getMethodName() + " finished in " + millis + "ms");

926

}

927

};

928

929

@Test

930

public void performanceTest() {

931

// Timing is automatically recorded

932

performOperation();

933

}

934

}

935

936

// Logging slow tests

937

public class SlowTestLogger extends Stopwatch {

938

private static final long THRESHOLD_MS = 1000;

939

940

@Override

941

protected void finished(long nanos, Description description) {

942

long millis = TimeUnit.NANOSECONDS.toMillis(nanos);

943

if (millis > THRESHOLD_MS) {

944

System.out.println("SLOW TEST: " + description.getMethodName()

945

+ " took " + millis + "ms");

946

}

947

}

948

}

949

```

950

951

### Verifier

952

953

Base class for rules that verify state after test execution. Similar to custom assertions.

954

955

```java { .api }

956

/**

957

* Base class for rules that verify conditions after test

958

*/

959

public abstract class Verifier implements TestRule {

960

/**

961

* Override to verify conditions after test

962

* Throw exception if verification fails

963

*/

964

protected void verify() throws Throwable;

965

}

966

```

967

968

**Usage Examples:**

969

970

```java

971

import org.junit.rules.Verifier;

972

import org.junit.Rule;

973

import org.junit.Test;

974

975

public class LogVerifier extends Verifier {

976

private Logger logger;

977

978

public LogVerifier(Logger logger) {

979

this.logger = logger;

980

}

981

982

@Override

983

protected void verify() {

984

if (logger.hasErrors()) {

985

throw new AssertionError("Test produced error logs: " + logger.getErrors());

986

}

987

}

988

}

989

990

public class VerifiedTest {

991

private Logger logger = new Logger();

992

993

@Rule

994

public Verifier logVerifier = new LogVerifier(logger);

995

996

@Test

997

public void testSomething() {

998

// Test code

999

// After test, verifier checks that no errors were logged

1000

}

1001

}

1002

1003

// State verification example

1004

public class StateVerifier extends Verifier {

1005

private SystemState state;

1006

1007

public StateVerifier(SystemState state) {

1008

this.state = state;

1009

}

1010

1011

@Override

1012

protected void verify() {

1013

if (!state.isClean()) {

1014

throw new AssertionError("System left in dirty state");

1015

}

1016

}

1017

}

1018

```

1019

1020

### DisableOnDebug

1021

1022

Wraps another rule and disables it when running in debug mode. Useful for timeout rules that interfere with debugging.

1023

1024

```java { .api }

1025

/**

1026

* Disables a rule when running in debug mode

1027

*/

1028

public class DisableOnDebug implements TestRule {

1029

/**

1030

* Create a rule that is disabled during debugging

1031

* @param rule - Rule to wrap

1032

*/

1033

public DisableOnDebug(TestRule rule);

1034

1035

/**

1036

* Check if currently debugging

1037

* @return true if debug mode detected

1038

*/

1039

public boolean isDebugging();

1040

}

1041

```

1042

1043

**Usage Examples:**

1044

1045

```java

1046

import org.junit.Rule;

1047

import org.junit.Test;

1048

import org.junit.rules.DisableOnDebug;

1049

import org.junit.rules.Timeout;

1050

1051

public class DebuggableTest {

1052

@Rule

1053

public TestRule timeout = new DisableOnDebug(Timeout.seconds(10));

1054

1055

@Test

1056

public void testWithTimeout() {

1057

// Timeout applies normally, but is disabled when debugging

1058

// so you can use breakpoints without timeout failures

1059

performOperation();

1060

}

1061

}

1062

```

1063

1064

## Types

1065

1066

```java { .api }

1067

/**

1068

* Represents a statement in test execution

1069

*/

1070

public abstract class Statement {

1071

/**

1072

* Execute the statement

1073

*/

1074

public abstract void evaluate() throws Throwable;

1075

}

1076

1077

/**

1078

* Legacy rule interface (prefer TestRule)

1079

*/

1080

@Deprecated

1081

public interface MethodRule {

1082

Statement apply(Statement base, FrameworkMethod method, Object target);

1083

}

1084

```

1085