or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

engine-management.mdindex.mdmock-configuration.mdmock-creation.mdstate-inspection.md

state-inspection.mddocs/

0

# State Inspection

1

2

State inspection and debugging functions for examining mock states, pending mocks, unmatched requests, and engine status. These functions are essential for debugging test failures, verifying mock behavior, and understanding pook's internal state during development and testing.

3

4

## Capabilities

5

6

### Mock State Functions

7

8

Functions for checking the status and completion state of registered mocks.

9

10

```python { .api }

11

def pending():

12

"""

13

Returns the number of pending mocks to be matched.

14

15

Pending mocks are mocks that have been registered but not yet

16

matched by any HTTP requests.

17

18

Returns:

19

int: Number of pending mocks

20

"""

21

22

def ispending():

23

"""

24

Returns the number of pending mocks to be matched (alias to pending()).

25

26

Returns:

27

int: Number of pending mocks

28

"""

29

30

def pending_mocks():

31

"""

32

Returns pending mocks to be matched.

33

34

Returns the actual Mock instances that are still waiting to be

35

matched by HTTP requests.

36

37

Returns:

38

list: List of pending Mock instances

39

"""

40

41

def isdone():

42

"""

43

Returns True if all registered mocks have been triggered.

44

45

A mock engine is considered "done" when all registered mocks

46

have been matched at least once (or up to their times() limit).

47

48

Returns:

49

bool: True if all mocks have been consumed, False otherwise

50

"""

51

```

52

53

Usage examples:

54

55

```python

56

import pook

57

import requests

58

59

# Setup multiple mocks

60

pook.activate()

61

pook.get('https://api.example.com/users').reply(200).json([])

62

pook.get('https://api.example.com/posts').reply(200).json([])

63

pook.post('https://api.example.com/users').reply(201)

64

65

print(f"Pending mocks: {pook.pending()}") # 3

66

print(f"Is pending: {pook.ispending()}") # 3 (alias)

67

print(f"All done: {pook.isdone()}") # False

68

69

# Make some requests

70

requests.get('https://api.example.com/users') # Matches first mock

71

print(f"Pending mocks: {pook.pending()}") # 2

72

print(f"All done: {pook.isdone()}") # False

73

74

requests.get('https://api.example.com/posts') # Matches second mock

75

print(f"Pending mocks: {pook.pending()}") # 1

76

77

requests.post('https://api.example.com/users') # Matches third mock

78

print(f"Pending mocks: {pook.pending()}") # 0

79

print(f"All done: {pook.isdone()}") # True

80

81

# Inspect pending mock details

82

pook.get('https://api.example.com/new').reply(200)

83

pending_list = pook.pending_mocks()

84

print(f"Pending mock URLs: {[mock.request.rawurl for mock in pending_list]}")

85

86

pook.off()

87

```

88

89

### Unmatched Request Functions

90

91

Functions for examining requests that didn't match any registered mocks, primarily useful in networking mode for debugging.

92

93

```python { .api }

94

def unmatched_requests():

95

"""

96

Returns a list of unmatched requests (only available in networking mode).

97

98

When networking mode is enabled, pook tracks requests that didn't

99

match any registered mocks. This is useful for debugging why

100

certain requests weren't intercepted.

101

102

Returns:

103

list: List of unmatched intercepted Request objects

104

"""

105

106

def unmatched():

107

"""

108

Returns the total number of unmatched requests intercepted by pook.

109

110

Returns:

111

int: Total number of unmatched requests

112

"""

113

114

def isunmatched():

115

"""

116

Returns True if there are unmatched requests, otherwise False.

117

118

Returns:

119

bool: True if any requests were intercepted but not matched

120

"""

121

```

122

123

Usage examples:

124

125

```python

126

import pook

127

import requests

128

129

# Enable networking to track unmatched requests

130

pook.activate()

131

pook.enable_network()

132

133

# Register some mocks

134

pook.get('https://api.example.com/users').reply(200).json([])

135

pook.post('https://api.example.com/users').reply(201)

136

137

# Make requests - some match, some don't

138

requests.get('https://api.example.com/users') # Matches mock

139

requests.get('https://api.example.com/posts') # No mock, goes to network

140

requests.delete('https://api.example.com/users/1') # No mock, goes to network

141

142

print(f"Unmatched count: {pook.unmatched()}") # 2

143

print(f"Has unmatched: {pook.isunmatched()}") # True

144

145

# Inspect unmatched requests

146

unmatched_reqs = pook.unmatched_requests()

147

for req in unmatched_reqs:

148

print(f"Unmatched: {req.method} {req.rawurl}")

149

150

# Output:

151

# Unmatched: GET https://api.example.com/posts

152

# Unmatched: DELETE https://api.example.com/users/1

153

154

pook.off()

155

```

156

157

### Engine Status Functions

158

159

Functions for checking the current state and activity status of pook's engine.

160

161

```python { .api }

162

def isactive():

163

"""

164

Returns True if pook is active and intercepting traffic, otherwise False.

165

166

The engine is active when activate() has been called and

167

before disable() or off() is called.

168

169

Returns:

170

bool: Current engine activation status

171

"""

172

```

173

174

Usage examples:

175

176

```python

177

import pook

178

179

print(f"Initially active: {pook.isactive()}") # False

180

181

pook.activate()

182

print(f"After activate: {pook.isactive()}") # True

183

184

pook.disable()

185

print(f"After disable: {pook.isactive()}") # False

186

187

pook.activate()

188

print(f"Reactivated: {pook.isactive()}") # True

189

190

pook.off() # Disable and reset

191

print(f"After off: {pook.isactive()}") # False

192

```

193

194

## Comprehensive Debugging Patterns

195

196

Practical patterns for using state inspection functions to debug complex testing scenarios.

197

198

### Test Assertion Patterns

199

200

```python

201

import pook

202

import requests

203

204

def test_all_mocks_consumed():

205

"""Ensure all expected API calls were made."""

206

207

pook.activate()

208

209

# Setup expected API calls

210

pook.get('https://api.example.com/config').reply(200).json({'version': '1.0'})

211

pook.get('https://api.example.com/users').reply(200).json([])

212

pook.post('https://api.example.com/analytics').reply(201)

213

214

# Run application code that should make these calls

215

# ... application code here ...

216

217

# Verify all mocks were consumed

218

if not pook.isdone():

219

pending = pook.pending_mocks()

220

urls = [mock.request.rawurl for mock in pending]

221

raise AssertionError(f"Unconsumed mocks: {urls}")

222

223

pook.off()

224

225

def test_no_unexpected_requests():

226

"""Ensure no unexpected network requests were made."""

227

228

pook.activate()

229

pook.enable_network()

230

231

# Setup expected mocks

232

pook.get('https://api.example.com/expected').reply(200)

233

234

# Run application code

235

# ... application code here ...

236

237

# Check for unexpected requests

238

if pook.isunmatched():

239

unmatched = pook.unmatched_requests()

240

unexpected = [f"{req.method} {req.rawurl}" for req in unmatched]

241

raise AssertionError(f"Unexpected requests: {unexpected}")

242

243

pook.off()

244

```

245

246

### Mock Lifecycle Monitoring

247

248

```python

249

import pook

250

import requests

251

252

class MockMonitor:

253

"""Helper class for monitoring mock state during tests."""

254

255

def __init__(self):

256

self.snapshots = []

257

258

def snapshot(self, label):

259

"""Take a snapshot of current mock state."""

260

snapshot = {

261

'label': label,

262

'active': pook.isactive(),

263

'pending': pook.pending(),

264

'unmatched': pook.unmatched(),

265

'done': pook.isdone()

266

}

267

self.snapshots.append(snapshot)

268

return snapshot

269

270

def report(self):

271

"""Generate a report of all snapshots."""

272

for snap in self.snapshots:

273

print(f"{snap['label']}: active={snap['active']}, "

274

f"pending={snap['pending']}, unmatched={snap['unmatched']}, "

275

f"done={snap['done']}")

276

277

# Usage

278

monitor = MockMonitor()

279

280

pook.activate()

281

pook.enable_network()

282

monitor.snapshot("After activation")

283

284

# Setup mocks

285

pook.get('https://api.example.com/step1').reply(200).json({'step': 1})

286

pook.get('https://api.example.com/step2').reply(200).json({'step': 2})

287

monitor.snapshot("After mock setup")

288

289

# Execute step 1

290

requests.get('https://api.example.com/step1')

291

monitor.snapshot("After step 1")

292

293

# Execute step 2

294

requests.get('https://api.example.com/step2')

295

monitor.snapshot("After step 2")

296

297

# Make unexpected request

298

requests.get('https://api.example.com/unexpected')

299

monitor.snapshot("After unexpected request")

300

301

monitor.report()

302

pook.off()

303

304

# Output:

305

# After activation: active=True, pending=0, unmatched=0, done=True

306

# After mock setup: active=True, pending=2, unmatched=0, done=False

307

# After step 1: active=True, pending=1, unmatched=0, done=False

308

# After step 2: active=True, pending=0, unmatched=0, done=True

309

# After unexpected request: active=True, pending=0, unmatched=1, done=True

310

```

311

312

### Detailed Mock Inspection

313

314

```python

315

import pook

316

import requests

317

318

def inspect_mock_details():

319

"""Detailed inspection of individual mock states."""

320

321

pook.activate()

322

323

# Create mocks with different configurations

324

mock1 = pook.get('https://api.example.com/limited').times(2).reply(200)

325

mock2 = pook.get('https://api.example.com/persistent').persist().reply(200)

326

mock3 = pook.get('https://api.example.com/unused').reply(200)

327

328

def print_mock_state(mock, name):

329

print(f"{name}:")

330

print(f" Done: {mock.isdone()}")

331

print(f" Matched: {mock.ismatched()}")

332

print(f" Total matches: {mock.total_matches}")

333

print(f" Calls: {mock.calls}")

334

335

print("Initial state:")

336

print_mock_state(mock1, "Limited mock (2 times)")

337

print_mock_state(mock2, "Persistent mock")

338

print_mock_state(mock3, "Unused mock")

339

340

# Make some requests

341

requests.get('https://api.example.com/limited') # First hit

342

requests.get('https://api.example.com/persistent') # First hit

343

344

print("\nAfter first requests:")

345

print_mock_state(mock1, "Limited mock")

346

print_mock_state(mock2, "Persistent mock")

347

print_mock_state(mock3, "Unused mock")

348

349

requests.get('https://api.example.com/limited') # Second hit (expires)

350

requests.get('https://api.example.com/persistent') # Second hit (continues)

351

352

print("\nAfter second requests:")

353

print_mock_state(mock1, "Limited mock")

354

print_mock_state(mock2, "Persistent mock")

355

print_mock_state(mock3, "Unused mock")

356

357

print(f"\nOverall state:")

358

print(f" Total pending: {pook.pending()}")

359

print(f" All done: {pook.isdone()}")

360

361

# List remaining pending mocks

362

pending = pook.pending_mocks()

363

if pending:

364

print(f" Pending mock URLs: {[m.request.rawurl for m in pending]}")

365

366

pook.off()

367

```

368

369

### Error Debugging Helpers

370

371

```python

372

import pook

373

import requests

374

375

def debug_mock_matching():

376

"""Helper for debugging why requests aren't matching mocks."""

377

378

pook.activate()

379

380

# Setup a mock with specific criteria

381

mock = pook.post('https://api.example.com/users') \

382

.header('Content-Type', 'application/json') \

383

.json({'name': 'John', 'age': 30}) \

384

.reply(201)

385

386

print(f"Mock registered. Pending: {pook.pending()}")

387

388

# Make a request that might not match

389

try:

390

response = requests.post('https://api.example.com/users',

391

json={'name': 'John', 'age': '30'}, # age as string

392

headers={'Content-Type': 'application/json'})

393

print(f"Request succeeded: {response.status_code}")

394

except Exception as e:

395

print(f"Request failed: {e}")

396

397

# Check what happened

398

print(f"After request - Pending: {pook.pending()}")

399

print(f"Mock matched: {mock.ismatched()}")

400

401

if not mock.ismatched():

402

print("Mock was not matched. Possible issues:")

403

print("- Request body didn't match expected JSON structure")

404

print("- Headers didn't match")

405

print("- URL didn't match")

406

print("- HTTP method didn't match")

407

408

pook.off()

409

410

def validate_test_cleanup():

411

"""Ensure proper test cleanup and isolation."""

412

413

def run_test():

414

pook.activate()

415

pook.get('https://api.example.com/test').reply(200)

416

# Simulate test that forgets cleanup

417

# pook.off() # Commented out - simulates forgotten cleanup

418

419

# Before test

420

print(f"Before test - Active: {pook.isactive()}, Pending: {pook.pending()}")

421

422

run_test()

423

424

# After test

425

print(f"After test - Active: {pook.isactive()}, Pending: {pook.pending()}")

426

427

if pook.isactive() or pook.pending() > 0:

428

print("WARNING: Test didn't clean up properly!")

429

print("This could affect other tests.")

430

pook.off() # Force cleanup

431

432

print(f"After cleanup - Active: {pook.isactive()}, Pending: {pook.pending()}")

433

```

434

435

## MatcherEngine Inspection

436

437

```python { .api }

438

class MatcherEngine:

439

"""

440

HTTP request matcher engine used by Mock to test if an intercepted

441

outgoing HTTP request should be mocked out.

442

"""

443

444

def match(self, request):

445

"""

446

Matches HTTP request against registered matchers.

447

448

Parameters:

449

- request: HTTP request to match

450

451

Returns:

452

tuple: (bool, list[str]) - Match success and error messages

453

"""

454

```

455

456

Usage examples:

457

458

```python

459

import pook

460

461

# Access matcher engine for detailed debugging

462

mock = pook.get('https://api.example.com/test')

463

mock.json({'required': 'field'}).reply(200)

464

465

# Simulate a request for testing

466

from pook import Request

467

test_request = Request(

468

method='GET',

469

url='https://api.example.com/test',

470

json={'different': 'field'}

471

)

472

473

# Test if request would match

474

success, errors = mock._matchers.match(test_request)

475

print(f"Would match: {success}")

476

if errors:

477

print(f"Match errors: {errors}")

478

```