or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

app.mdflags.mdindex.mdlogging.mdtesting.md

testing.mddocs/

0

# Testing Utilities

1

2

Comprehensive testing framework extending Python's unittest with additional assertions, parameterized testing, temporary file management, flag state management, and enhanced test discovery and execution capabilities.

3

4

## Capabilities

5

6

### Enhanced Test Case

7

8

Extended test case class with additional assertions and utilities for absl-based applications.

9

10

```python { .api }

11

class TestCase(unittest.TestCase):

12

"""

13

Enhanced test case class extending unittest.TestCase.

14

15

Provides additional assertions, temporary file management,

16

and integration with absl flags and logging systems.

17

"""

18

19

def setUp(self):

20

"""Set up test fixtures before each test method."""

21

22

def tearDown(self):

23

"""Clean up after each test method."""

24

25

def create_tempdir(self, name=None, cleanup=TempFileCleanup.ALWAYS):

26

"""

27

Create a temporary directory for the test.

28

29

Args:

30

name (str): Optional name for the directory

31

cleanup (TempFileCleanup): When to clean up the directory

32

33

Returns:

34

_TempDir: Temporary directory object

35

"""

36

37

def create_tempfile(self, file_path=None, content=None, mode='w', encoding='utf-8',

38

errors='strict', cleanup=TempFileCleanup.ALWAYS):

39

"""

40

Create a temporary file for the test.

41

42

Args:

43

file_path (str): Optional path within temp directory

44

content (str): Optional content to write to file

45

mode (str): File open mode

46

encoding (str): File encoding

47

errors (str): Error handling mode

48

cleanup (TempFileCleanup): When to clean up the file

49

50

Returns:

51

_TempFile: Temporary file object

52

"""

53

54

# Additional assertion methods

55

def assertEmpty(self, container, msg=None):

56

"""Assert that a container is empty."""

57

58

def assertNotEmpty(self, container, msg=None):

59

"""Assert that a container is not empty."""

60

61

def assertLen(self, container, expected_len, msg=None):

62

"""Assert that a container has the expected length."""

63

64

def assertStartsWith(self, actual, expected_start, msg=None):

65

"""Assert that a string starts with expected prefix."""

66

67

def assertEndsWith(self, actual, expected_end, msg=None):

68

"""Assert that a string ends with expected suffix."""

69

70

def assertSequenceStartsWith(self, prefix, whole, msg=None):

71

"""Assert that a sequence starts with expected prefix sequence."""

72

73

def assertContainsSubset(self, expected_subset, actual_container, msg=None):

74

"""Assert that actual_container contains all elements in expected_subset."""

75

76

def assertNoCommonElements(self, expected_seq, actual_seq, msg=None):

77

"""Assert that two sequences have no common elements."""

78

79

def assertItemsEqual(self, expected_seq, actual_seq, msg=None):

80

"""Assert that two sequences have the same elements (ignoring order)."""

81

82

def assertCountEqual(self, expected_seq, actual_seq, msg=None):

83

"""Assert that two sequences have the same elements (ignoring order)."""

84

85

def assertSameElements(self, expected_seq, actual_seq, msg=None):

86

"""Assert that two sequences have the same elements (ignoring order)."""

87

88

def assertSetEqual(self, expected_set, actual_set, msg=None):

89

"""Assert that two sets are equal."""

90

91

def assertListEqual(self, expected_list, actual_list, msg=None):

92

"""Assert that two lists are equal."""

93

94

def assertTupleEqual(self, expected_tuple, actual_tuple, msg=None):

95

"""Assert that two tuples are equal."""

96

97

def assertSequenceEqual(self, expected_seq, actual_seq, msg=None, seq_type=None):

98

"""Assert that two sequences are equal."""

99

100

def assertDictEqual(self, expected_dict, actual_dict, msg=None):

101

"""Assert that two dictionaries are equal."""

102

103

def assertDictContainsSubset(self, expected_subset, actual_dict, msg=None):

104

"""Assert that actual_dict contains all key-value pairs in expected_subset."""

105

106

def assertUrlEqual(self, expected_url, actual_url, msg=None):

107

"""Assert that two URLs are equal (handling URL encoding differences)."""

108

109

def assertSameStructure(self, expected, actual, abridge=True, msg=None):

110

"""Assert that two nested structures have the same shape."""

111

112

def assertJsonEqual(self, expected, actual, msg=None):

113

"""Assert that two JSON-serializable objects are equal."""

114

115

def assertBetween(self, value, lower_bound, upper_bound, msg=None):

116

"""Assert that a value is between lower_bound and upper_bound (inclusive)."""

117

118

def assertLoggedLines(self, expected_logs, stream=None, min_level=None):

119

"""Assert that specific log lines were logged."""

120

121

def assertRaisesWithLiteralMatch(self, expected_exception, expected_exception_message, callable_obj=None, *args, **kwargs):

122

"""Assert that an exception is raised with exact message match."""

123

124

def assertRaisesWithPredicateMatch(self, exception_predicate, callable_obj=None, *args, **kwargs):

125

"""Assert that an exception is raised matching a predicate function."""

126

```

127

128

### Test Runner

129

130

Main entry point for running absl-based tests with enhanced features.

131

132

```python { .api }

133

def main(*args, **kwargs):

134

"""

135

Main test runner function.

136

137

Automatically discovers and runs tests with absl integration,

138

flag parsing, and enhanced output formatting.

139

140

Args:

141

*args: Arguments passed to unittest.main

142

**kwargs: Keyword arguments passed to unittest.main

143

"""

144

145

def run_tests(test_runner=None, argv=None, args=None, **kwargs):

146

"""

147

Run tests with custom test runner and arguments.

148

149

Args:

150

test_runner: Custom test runner class

151

argv: Command line arguments

152

args: Additional arguments

153

**kwargs: Additional keyword arguments

154

155

Returns:

156

unittest.TestResult: Test execution results

157

"""

158

159

class TestLoader(unittest.TestLoader):

160

"""

161

Enhanced test loader with additional discovery capabilities.

162

"""

163

164

def loadTestsFromModule(self, module, *args, **kwargs):

165

"""Load tests from a module with enhanced discovery."""

166

```

167

168

### Temporary File Management

169

170

Utilities for managing temporary files and directories in tests.

171

172

```python { .api }

173

class TempFileCleanup(enum.Enum):

174

"""Enumeration for temporary file cleanup behavior."""

175

176

ALWAYS = 'always' # Clean up after every test

177

SUCCESS = 'success' # Clean up only on test success

178

FAILURE = 'failure' # Clean up only on test failure

179

180

class _TempDir:

181

"""Temporary directory manager for tests."""

182

183

def __init__(self, path, cleanup):

184

"""Initialize temporary directory."""

185

186

@property

187

def full_path(self):

188

"""Get the full path to the temporary directory."""

189

190

def create_file(self, file_path, content='', mode='w'):

191

"""Create a file within the temporary directory."""

192

193

def mkdir(self, dir_path):

194

"""Create a subdirectory within the temporary directory."""

195

196

class _TempFile:

197

"""Temporary file manager for tests."""

198

199

def __init__(self, path, cleanup):

200

"""Initialize temporary file."""

201

202

@property

203

def full_path(self):

204

"""Get the full path to the temporary file."""

205

206

def read_text(self, encoding='utf-8'):

207

"""Read the file contents as text."""

208

209

def write_text(self, content, encoding='utf-8'):

210

"""Write text content to the file."""

211

```

212

213

### Test Utilities

214

215

Additional utility functions for testing.

216

217

```python { .api }

218

def expectedFailureIf(condition, reason):

219

"""

220

Decorator to mark a test as expected failure under certain conditions.

221

222

Args:

223

condition (bool): If True, mark test as expected failure

224

reason (str): Reason for expected failure

225

226

Returns:

227

Decorator function

228

"""

229

230

def skipThisClass(reason):

231

"""

232

Decorator to skip an entire test class.

233

234

Args:

235

reason (str): Reason for skipping the class

236

237

Returns:

238

Decorator function

239

"""

240

241

def get_default_test_random_seed():

242

"""

243

Get the default random seed for tests.

244

245

Returns:

246

int: Default random seed value

247

"""

248

249

def get_default_test_srcdir():

250

"""

251

Get the default test source directory.

252

253

Returns:

254

str: Path to test source directory

255

"""

256

257

def get_default_test_tmpdir():

258

"""

259

Get the default test temporary directory.

260

261

Returns:

262

str: Path to test temporary directory

263

"""

264

```

265

266

## Parameterized Testing

267

268

Utilities for creating parameterized tests with multiple test cases from a single test method.

269

270

### Parameterized Test Case

271

272

```python { .api }

273

class parameterized.TestCase(absltest.TestCase):

274

"""

275

Test case class with parameterized testing support.

276

277

Inherits from absltest.TestCase and adds parameterized test generation.

278

"""

279

280

class parameterized.TestGeneratorMetaclass(type):

281

"""Metaclass for generating parameterized tests."""

282

```

283

284

### Parameterization Decorators

285

286

```python { .api }

287

def parameterized.parameters(*testcases):

288

"""

289

Decorator to parameterize a test method.

290

291

Args:

292

*testcases: Test case parameters, each can be:

293

- Single value

294

- Tuple/list of values

295

- Dictionary of keyword arguments

296

297

Returns:

298

Decorator function

299

"""

300

301

def parameterized.named_parameters(*testcases):

302

"""

303

Decorator to parameterize a test method with named test cases.

304

305

Args:

306

*testcases: Named test cases, each should be a tuple/list where

307

the first element is the test name and remaining elements

308

are the test parameters

309

310

Returns:

311

Decorator function

312

"""

313

314

def parameterized.product(*kwargs_seqs, **testgrid):

315

"""

316

Generate test parameters from the Cartesian product of parameter sets.

317

318

Args:

319

*kwargs_seqs: Sequences of keyword argument dictionaries

320

**testgrid: Named parameter sequences for grid generation

321

322

Returns:

323

Generator of parameter combinations

324

"""

325

```

326

327

### Parameterization Utilities

328

329

```python { .api }

330

def parameterized.CoopTestCase(other_base_class):

331

"""

332

Create a cooperative test case class that inherits from both

333

parameterized.TestCase and another base class.

334

335

Args:

336

other_base_class (type): Other base class to inherit from

337

338

Returns:

339

type: New test case class

340

"""

341

```

342

343

## Flag State Management

344

345

Utilities for saving and restoring flag states during testing.

346

347

### Flag Saver Decorators

348

349

```python { .api }

350

def flagsaver.flagsaver(func=None, **overrides):

351

"""

352

Decorator to save and restore flag values around test execution.

353

354

Can be used as @flagsaver.flagsaver or @flagsaver.flagsaver(flag_name=value)

355

356

Args:

357

func (callable): Function to wrap (when used without arguments)

358

**overrides: Flag values to override during test execution

359

360

Returns:

361

Decorator function or wrapped function

362

"""

363

364

def flagsaver.as_parsed(*args, **kwargs):

365

"""

366

Decorator to set flag values as if parsed from command line.

367

368

Args:

369

*args: Tuples of (flag_holder, value) or (flag_holder, [values])

370

**kwargs: Flag name to value mappings

371

372

Returns:

373

Decorator function

374

"""

375

```

376

377

### Flag State Management Functions

378

379

```python { .api }

380

def flagsaver.save_flag_values(flag_values, **overrides):

381

"""

382

Save current flag values and optionally override some values.

383

384

Args:

385

flag_values (FlagValues): Flag values container to save

386

**overrides: Flag values to override

387

388

Returns:

389

dict: Saved flag state

390

"""

391

392

def flagsaver.restore_flag_values(saved_flag_values, flag_values):

393

"""

394

Restore previously saved flag values.

395

396

Args:

397

saved_flag_values (dict): Previously saved flag state

398

flag_values (FlagValues): Flag values container to restore

399

"""

400

```

401

402

## Usage Examples

403

404

### Basic Test Case

405

406

```python

407

from absl.testing import absltest

408

409

class MyTest(absltest.TestCase):

410

411

def test_basic_functionality(self):

412

"""Test basic functionality."""

413

result = my_function('input')

414

self.assertEqual(result, 'expected_output')

415

416

def test_with_temp_files(self):

417

"""Test using temporary files."""

418

temp_dir = self.create_tempdir()

419

temp_file = temp_dir.create_file('test.txt', 'content')

420

421

# Use temp_file.full_path for file operations

422

result = process_file(temp_file.full_path)

423

self.assertIsNotNone(result)

424

425

if __name__ == '__main__':

426

absltest.main()

427

```

428

429

### Parameterized Testing

430

431

```python

432

from absl.testing import absltest

433

from absl.testing import parameterized

434

435

class ParameterizedTest(parameterized.TestCase):

436

437

@parameterized.parameters(

438

(1, 2, 3),

439

(4, 5, 9),

440

(10, 20, 30),

441

)

442

def test_addition(self, a, b, expected):

443

"""Test addition with multiple parameter sets."""

444

result = add(a, b)

445

self.assertEqual(result, expected)

446

447

@parameterized.named_parameters(

448

('positive_numbers', 5, 3, 8),

449

('negative_numbers', -2, -3, -5),

450

('mixed_numbers', -1, 4, 3),

451

)

452

def test_named_addition(self, a, b, expected):

453

"""Test addition with named parameter sets."""

454

result = add(a, b)

455

self.assertEqual(result, expected)

456

457

@parameterized.product(

458

x=[1, 2, 3],

459

y=[10, 20],

460

operation=['add', 'multiply']

461

)

462

def test_operations_grid(self, x, y, operation):

463

"""Test operations using parameter grid."""

464

if operation == 'add':

465

result = x + y

466

else:

467

result = x * y

468

self.assertGreater(result, 0)

469

470

if __name__ == '__main__':

471

absltest.main()

472

```

473

474

### Flag Testing

475

476

```python

477

from absl import flags

478

from absl.testing import absltest

479

from absl.testing import flagsaver

480

481

FLAGS = flags.FLAGS

482

flags.DEFINE_string('test_flag', 'default', 'Test flag.')

483

484

class FlagTest(absltest.TestCase):

485

486

@flagsaver.flagsaver

487

def test_with_flag_override(self):

488

"""Test with flag value override."""

489

FLAGS.test_flag = 'test_value'

490

result = function_that_uses_flag()

491

self.assertEqual(result, 'expected_with_test_value')

492

# Flag is automatically restored after test

493

494

@flagsaver.flagsaver(test_flag='override_value')

495

def test_with_decorator_override(self):

496

"""Test with decorator-specified flag override."""

497

result = function_that_uses_flag()

498

self.assertEqual(result, 'expected_with_override_value')

499

500

@flagsaver.as_parsed(('test_flag', 'parsed_value'))

501

def test_with_parsed_flag(self):

502

"""Test with flag set as if parsed from command line."""

503

result = function_that_uses_flag()

504

self.assertEqual(result, 'expected_with_parsed_value')

505

506

if __name__ == '__main__':

507

absltest.main()

508

```

509

510

### Temporary File Testing

511

512

```python

513

from absl.testing import absltest

514

import os

515

516

class FileTest(absltest.TestCase):

517

518

def test_file_processing(self):

519

"""Test file processing with temporary files."""

520

# Create temporary directory

521

temp_dir = self.create_tempdir()

522

523

# Create test files

524

input_file = temp_dir.create_file('input.txt', 'test content')

525

output_file_path = os.path.join(temp_dir.full_path, 'output.txt')

526

527

# Test file processing

528

process_file(input_file.full_path, output_file_path)

529

530

# Verify output

531

self.assertTrue(os.path.exists(output_file_path))

532

with open(output_file_path, 'r') as f:

533

content = f.read()

534

self.assertIn('processed', content)

535

536

if __name__ == '__main__':

537

absltest.main()

538

```

539

540

### Test Discovery and Execution

541

542

```python

543

# test_runner.py

544

from absl.testing import absltest

545

546

if __name__ == '__main__':

547

# Automatically discover and run all tests

548

absltest.main()

549

```

550

551

Command line usage:

552

```bash

553

# Run all tests

554

python test_runner.py

555

556

# Run specific test class

557

python test_runner.py MyTest

558

559

# Run specific test method

560

python test_runner.py MyTest.test_method

561

562

# Run with verbose output

563

python test_runner.py --verbose

564

565

# Run with specific flags

566

python test_runner.py --test_flag=value

567

```