or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

assertions.mdconfiguration.mdfixtures.mdindex.mdmarks.mdreporting.mdtest-collection.mdtest-utilities.mdtesting-functions.mdwarnings.md

test-collection.mddocs/

0

# Test Collection and Execution

1

2

Collection tree components for test discovery, organization, and execution. The collection system builds a hierarchical tree of collectors and items that represent the structure of your test suite.

3

4

## Capabilities

5

6

### Base Collection Classes

7

8

Foundation classes for all collection tree components.

9

10

```python { .api }

11

class Node:

12

"""Base class for all collection tree components."""

13

14

# Core attributes

15

name: str # Node name

16

parent: Node | None # Parent node

17

config: Config # pytest configuration

18

session: Session # Test session

19

path: Path # File system path

20

nodeid: str # Unique node identifier

21

22

@classmethod

23

def from_parent(cls, parent: Node, **kwargs):

24

"""Create node with parent reference."""

25

26

def listchain(self) -> list[Node]:

27

"""Return list of all parent nodes."""

28

29

def add_marker(self, marker) -> None:

30

"""Add marker to this node."""

31

32

def iter_markers(self, name: str | None = None):

33

"""Iterate over markers."""

34

35

def get_closest_marker(self, name: str):

36

"""Get closest marker with given name."""

37

38

class Collector(Node, abc.ABC):

39

"""Base class for collection tree internal nodes.

40

41

Collectors create children through collect() and iteratively build

42

the collection tree.

43

"""

44

45

class CollectError(Exception):

46

"""An error during collection, contains a custom message."""

47

48

@abc.abstractmethod

49

def collect(self) -> Iterable[Item | Collector]:

50

"""

51

Collect children (items and collectors) for this collector.

52

53

Returns:

54

Iterable of Item or Collector objects

55

"""

56

57

def repr_failure(self, excinfo: ExceptionInfo[BaseException]) -> str | TerminalRepr:

58

"""

59

Return a representation of a collection failure.

60

61

Parameters:

62

- excinfo: Exception information for the failure

63

64

Returns:

65

String or TerminalRepr representation of the failure

66

"""

67

68

class Item(Node, abc.ABC):

69

"""Base class for collection tree leaf nodes (test items).

70

71

Note that for a single function there might be multiple test invocation items.

72

"""

73

74

nextitem = None # Reference to next item

75

76

def __init__(

77

self,

78

name,

79

parent=None,

80

config: Config | None = None,

81

session: Session | None = None,

82

nodeid: str | None = None,

83

**kw,

84

) -> None:

85

"""

86

Initialize test item.

87

88

Parameters:

89

- name: Item name

90

- parent: Parent collector

91

- config: pytest configuration

92

- session: Test session

93

- nodeid: Node identifier

94

"""

95

96

@abc.abstractmethod

97

def runtest(self) -> None:

98

"""

99

Run the test case (abstract method).

100

101

Must be implemented by subclasses to execute the actual test.

102

"""

103

104

def setup(self) -> None:

105

"""Set up test execution."""

106

107

def teardown(self) -> None:

108

"""Tear down after test execution."""

109

110

def add_report_section(self, when: str, key: str, content: str) -> None:

111

"""

112

Add report section to test results.

113

114

Parameters:

115

- when: Test phase ("setup", "call", "teardown")

116

- key: Section identifier

117

- content: Section content

118

"""

119

120

def reportinfo(self) -> tuple[os.PathLike[str] | str, int | None, str]:

121

"""

122

Return location information for reporting.

123

124

Returns:

125

Tuple of (filename, line_number, test_name)

126

"""

127

128

@property

129

def location(self) -> tuple[str, int | None, str]:

130

"""Get test location as (relfspath, lineno, testname)."""

131

132

# Attributes

133

user_properties: list[tuple[str, object]] # User-defined properties

134

_report_sections: list[tuple[str, str, str]] # Report sections

135

```

136

137

### File System Collectors

138

139

Collectors for file system entities.

140

141

```python { .api }

142

class FSCollector(Collector, abc.ABC):

143

"""Base class for filesystem-based collectors."""

144

145

def __init__(

146

self,

147

path: Path,

148

parent: Collector | None = None,

149

config: Config | None = None,

150

session: Session | None = None,

151

nodeid: str | None = None,

152

) -> None:

153

"""Initialize filesystem collector with path."""

154

155

class File(FSCollector, abc.ABC):

156

"""Base class for collecting tests from files."""

157

158

@abc.abstractmethod

159

def collect(self) -> Iterable[Item | Collector]:

160

"""Collect tests from file (abstract method)."""

161

162

class Directory(FSCollector, abc.ABC):

163

"""Base class for collecting from directories."""

164

165

@abc.abstractmethod

166

def collect(self) -> Iterable[Item | Collector]:

167

"""Collect from directory contents (abstract method)."""

168

169

class Dir(Directory):

170

"""Directory collector implementation.

171

172

Used for directories without __init__.py files.

173

"""

174

175

def collect(self) -> Iterable[nodes.Item | nodes.Collector]:

176

"""

177

Collect files and subdirectories.

178

179

Returns:

180

Iterable of collectors for Python files and subdirectories

181

"""

182

183

@classmethod

184

def from_parent(cls, parent: nodes.Collector, *, path: Path) -> Self:

185

"""

186

Create Dir collector from parent.

187

188

Parameters:

189

- parent: Parent collector

190

- path: Directory path

191

192

Returns:

193

Dir collector instance

194

"""

195

```

196

197

### Python-Specific Collectors

198

199

Collectors specialized for Python test code.

200

201

```python { .api }

202

class PyCollector(Collector, abc.ABC):

203

"""Base class for Python-specific collectors."""

204

205

def _getobj(self):

206

"""Import and return the Python object."""

207

208

class Module(nodes.File, PyCollector):

209

"""Collector for test classes and functions in Python modules."""

210

211

def collect(self) -> Iterable[nodes.Item | nodes.Collector]:

212

"""

213

Collect test classes and functions from module.

214

215

Returns:

216

Iterable of Class collectors and Function items

217

"""

218

219

def _getobj(self):

220

"""

221

Import and return the module object.

222

223

Returns:

224

The imported module

225

"""

226

227

def _register_setup_module_fixture(self) -> None:

228

"""Register setup/teardown module fixtures."""

229

230

def _register_setup_function_fixture(self) -> None:

231

"""Register setup/teardown function fixtures."""

232

233

class Package(nodes.Directory):

234

"""Collector for Python packages (directories with __init__.py)."""

235

236

def collect(self) -> Iterable[nodes.Item | nodes.Collector]:

237

"""

238

Collect modules and subpackages.

239

240

Returns:

241

Iterable of Module and Package collectors

242

"""

243

244

def setup(self) -> None:

245

"""Set up package-level fixtures."""

246

247

class Class(PyCollector):

248

"""Collector for test methods (and nested classes) in Python classes."""

249

250

def collect(self) -> Iterable[nodes.Item | nodes.Collector]:

251

"""

252

Collect test methods from class.

253

254

Returns:

255

Iterable of Function items and nested Class collectors

256

"""

257

258

def newinstance(self):

259

"""

260

Create new instance of the class.

261

262

Returns:

263

New instance of the test class

264

"""

265

266

@classmethod

267

def from_parent(cls, parent, *, name, obj=None, **kw) -> Self:

268

"""

269

Create Class collector from parent.

270

271

Parameters:

272

- parent: Parent collector

273

- name: Class name

274

- obj: Class object (optional)

275

276

Returns:

277

Class collector instance

278

"""

279

280

def _register_setup_class_fixture(self) -> None:

281

"""Register class-level setup/teardown fixtures."""

282

283

def _register_setup_method_fixture(self) -> None:

284

"""Register method-level setup/teardown fixtures."""

285

286

class Function(Item):

287

"""Item for Python test functions."""

288

289

# Core attributes

290

function: Callable # Test function object

291

fixturenames: frozenset[str] # Required fixture names

292

callspec: CallSpec2 | None # Parametrization info

293

294

def runtest(self) -> None:

295

"""Execute the test function."""

296

297

def setup(self) -> None:

298

"""Set up fixtures and test environment."""

299

300

def teardown(self) -> None:

301

"""Tear down fixtures and clean up."""

302

```

303

304

### Session Management

305

306

Root-level session management for test execution coordination.

307

308

```python { .api }

309

class Session(Collector):

310

"""Root of collection tree, collects initial paths."""

311

312

def collect(self) -> list[Node]:

313

"""Collect from initial file paths."""

314

315

def pytest_runtest_protocol(self, item: Item) -> bool:

316

"""Run test protocol for item."""

317

318

def pytest_collection_modifyitems(self, items: list[Item]) -> None:

319

"""Modify collected items."""

320

```

321

322

### Test Parametrization

323

324

Metafunc object for parametrizing tests during collection.

325

326

```python { .api }

327

class Metafunc:

328

"""Used in pytest_generate_tests hook for parametrizing tests."""

329

330

# Core attributes

331

function: Callable # Test function

332

module: Any # Test module

333

cls: type | None # Test class (if applicable)

334

config: Config # pytest configuration

335

definition: FunctionDefinition # Function definition

336

fixturenames: frozenset[str] # Fixture names used by function

337

338

def parametrize(

339

self,

340

argnames: str | list[str] | tuple[str, ...],

341

argvalues,

342

*,

343

indirect: bool | list[str] = False,

344

ids=None,

345

scope: str | None = None

346

) -> None:

347

"""Parametrize test function."""

348

349

def addcall(self, **kwargs) -> None:

350

"""Add individual test call (deprecated, use parametrize)."""

351

```

352

353

**Usage Example:**

354

355

```python

356

# conftest.py

357

def pytest_generate_tests(metafunc):

358

if "browser" in metafunc.fixturenames:

359

metafunc.parametrize(

360

"browser",

361

["chrome", "firefox", "safari"],

362

ids=["Chrome", "Firefox", "Safari"]

363

)

364

365

if "database" in metafunc.fixturenames:

366

metafunc.parametrize(

367

"database",

368

[("sqlite", ":memory:"), ("postgresql", "test_db")],

369

ids=["SQLite", "PostgreSQL"]

370

)

371

372

# Test will run 6 times (3 browsers × 2 databases)

373

def test_web_app(browser, database):

374

pass

375

```

376

377

### Doctest Integration

378

379

Support for running doctests as part of the test suite.

380

381

```python { .api }

382

class DoctestItem(Item):

383

"""Test item for executing doctests."""

384

385

def __init__(

386

self,

387

name: str,

388

parent: DoctestTextfile | DoctestModule,

389

runner: doctest.DocTestRunner,

390

dtest: doctest.DocTest,

391

) -> None:

392

"""

393

Initialize doctest item.

394

395

Parameters:

396

- name: Item name

397

- parent: Parent collector (DoctestTextfile or DoctestModule)

398

- runner: Doctest runner

399

- dtest: Doctest object

400

"""

401

402

# Attributes

403

runner: doctest.DocTestRunner # Doctest runner

404

dtest: doctest.DocTest # Doctest object

405

obj = None # No underlying Python object

406

_fixtureinfo: fixtures.FuncFixtureInfo # Fixture information

407

fixturenames: frozenset[str] # Required fixture names

408

409

def runtest(self) -> None:

410

"""

411

Execute the doctest.

412

413

Runs the doctest using the configured runner and handles

414

any failures according to pytest conventions.

415

"""

416

417

def setup(self) -> None:

418

"""Set up doctest fixtures and environment."""

419

420

def repr_failure(self, excinfo: ExceptionInfo[BaseException]) -> str | TerminalRepr:

421

"""

422

Format doctest failures for display.

423

424

Parameters:

425

- excinfo: Exception information

426

427

Returns:

428

Formatted failure representation

429

"""

430

431

def reportinfo(self) -> tuple[os.PathLike[str] | str, int | None, str]:

432

"""

433

Get doctest location information for reporting.

434

435

Returns:

436

Tuple of (filename, line_number, doctest_name)

437

"""

438

439

@classmethod

440

def from_parent(

441

cls,

442

parent: DoctestTextfile | DoctestModule,

443

*,

444

name: str,

445

runner: doctest.DocTestRunner,

446

dtest: doctest.DocTest,

447

) -> Self:

448

"""

449

Create DoctestItem from parent collector.

450

451

Parameters:

452

- parent: Parent collector

453

- name: Item name

454

- runner: Doctest runner

455

- dtest: Doctest object

456

457

Returns:

458

DoctestItem instance

459

"""

460

```

461

462

## Collection Process

463

464

The collection process follows these steps:

465

466

1. **Start Collection**: Session.collect() begins from initial paths

467

2. **Directory Collection**: Dir collectors process directories

468

3. **File Collection**: Module collectors process Python files

469

4. **Class Collection**: Class collectors process test classes

470

5. **Function Collection**: Function collectors process test functions

471

6. **Parametrization**: Metafunc.parametrize() creates multiple test variants

472

7. **Item Modification**: pytest_collection_modifyitems hook allows final changes

473

474

**Usage Example:**

475

476

```python

477

# Custom collector example

478

class YamlFile(pytest.File):

479

def collect(self):

480

# Parse YAML file and create test items

481

raw = yaml.safe_load(self.path.open())

482

for name, spec in raw.items():

483

yield YamlTest.from_parent(self, name=name, spec=spec)

484

485

class YamlTest(pytest.Item):

486

def __init__(self, name, parent, spec):

487

super().__init__(name, parent)

488

self.spec = spec

489

490

def runtest(self):

491

# Execute test based on YAML spec

492

pass

493

494

def pytest_collect_file(parent, path):

495

if path.suffix == ".yaml" and path.name.startswith("test_"):

496

return YamlFile.from_parent(parent, path=path)

497

```

498

499

## Types

500

501

```python { .api }

502

from typing import Any, Callable

503

from pathlib import Path

504

505

class CallSpec2:

506

"""Represents parametrized test call specification."""

507

508

# Attributes

509

params: dict[str, Any] # Parameter values

510

funcargs: dict[str, Any] # Function arguments

511

id: str | None # Parameter set ID

512

marks: list[Mark] # Applied marks

513

514

def setmulti(self, **kwargs) -> None:

515

"""Set multiple parameters."""

516

517

class FunctionDefinition:

518

"""Definition of a test function for collection."""

519

520

# Attributes

521

name: str # Function name

522

obj: Callable # Function object

523

parent: Node # Parent collector

524

525

def getparent(self, cls: type) -> Node | None:

526

"""Get parent of specific type."""

527

```