or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

authentication.mdclient-management.mdconfiguration.mdexception-handling.mdhttp-clients.mdindex.mdresponse-handling.mdspec-loading.mdtesting-utilities.md

testing-utilities.mddocs/

0

# Testing Utilities

1

2

Mock objects and integration testing base classes for testing applications that use bravado. These utilities provide comprehensive testing support including response mocks, fallback result testing, and integration test fixtures for both synchronous and asynchronous HTTP clients.

3

4

## Capabilities

5

6

### Response Mocks

7

8

Mock objects that simulate bravado response behavior for unit testing.

9

10

#### IncomingResponseMock

11

12

Mock implementation of IncomingResponse for creating test responses.

13

14

```python { .api }

15

class IncomingResponseMock(IncomingResponse):

16

def __init__(self, status_code: int, **kwargs): ...

17

```

18

19

**Parameters:**

20

- `status_code` (int): HTTP status code for the mock response

21

- `**kwargs`: Additional response attributes (text, headers, etc.)

22

23

**Usage Example:**

24

25

```python

26

from bravado.testing.response_mocks import IncomingResponseMock

27

28

# Create mock response

29

mock_response = IncomingResponseMock(

30

status_code=200,

31

text='{"name": "Fluffy", "status": "available"}',

32

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

33

)

34

35

print(mock_response.status_code) # 200

36

print(mock_response.text) # {"name": "Fluffy", "status": "available"}

37

```

38

39

#### BravadoResponseMock

40

41

Mock that behaves like both HttpFuture.response() method and BravadoResponse object.

42

43

```python { .api }

44

class BravadoResponseMock:

45

def __init__(self, result, metadata=None): ...

46

def __call__(self, timeout: float = None, fallback_result=None, exceptions_to_catch: tuple = None) -> 'BravadoResponseMock': ...

47

@property

48

def result(self): ...

49

@property

50

def metadata(self) -> BravadoResponseMetadata: ...

51

```

52

53

**Parameters:**

54

- `result`: The mock result data to return

55

- `metadata`: BravadoResponseMetadata instance (optional)

56

- `timeout` (float): Timeout parameter (ignored in mock)

57

- `fallback_result`: Fallback result (ignored unless forced)

58

- `exceptions_to_catch` (tuple): Exception types (ignored in mock)

59

60

**Usage Example:**

61

62

```python

63

from bravado.testing.response_mocks import BravadoResponseMock

64

65

# Create mock response

66

mock_result = {'name': 'Fluffy', 'status': 'available'}

67

mock_response = BravadoResponseMock(mock_result)

68

69

# Use as HttpFuture.response() replacement

70

response = mock_response() # Call like future.response()

71

pet_data = response.result # Access result like normal BravadoResponse

72

73

# Or use directly as BravadoResponse

74

pet_data = mock_response.result

75

```

76

77

#### FallbackResultBravadoResponseMock

78

79

Mock that always triggers fallback result behavior, useful for testing error handling and resilience.

80

81

```python { .api }

82

class FallbackResultBravadoResponseMock:

83

def __init__(self, exception=BravadoTimeoutError(), metadata=None): ...

84

def __call__(self, timeout: float = None, fallback_result=None, exceptions_to_catch: tuple = None) -> 'FallbackResultBravadoResponseMock': ...

85

@property

86

def result(self): ...

87

@property

88

def metadata(self) -> BravadoResponseMetadata: ...

89

```

90

91

**Parameters:**

92

- `exception`: Exception to simulate (defaults to BravadoTimeoutError)

93

- `metadata`: BravadoResponseMetadata instance (optional)

94

95

**Usage Example:**

96

97

```python

98

from bravado.testing.response_mocks import FallbackResultBravadoResponseMock

99

from bravado.exception import BravadoTimeoutError

100

101

# Mock that simulates timeout and uses fallback

102

fallback_mock = FallbackResultBravadoResponseMock(

103

exception=BravadoTimeoutError("Request timeout")

104

)

105

106

# Test fallback behavior

107

fallback_data = {'name': 'Unknown', 'status': 'unavailable'}

108

response = fallback_mock(fallback_result=fallback_data)

109

110

assert response.result == fallback_data

111

assert response.metadata.is_fallback_result is True

112

```

113

114

### Integration Testing Base Classes

115

116

Comprehensive integration testing framework for testing bravado clients with real HTTP servers.

117

118

#### IntegrationTestingServicesAndClient

119

120

Pytest fixtures for setting up HTTP servers and clients for integration testing.

121

122

```python { .api }

123

class IntegrationTestingServicesAndClient:

124

@pytest.fixture(scope='session')

125

def swagger_http_server(self): ...

126

127

@pytest.fixture(scope='session')

128

def not_answering_http_server(self): ...

129

130

@pytest.fixture(params=['result', 'response'])

131

def result_getter(self, request): ...

132

```

133

134

**Fixtures:**

135

- `swagger_http_server`: Session-scoped HTTP server serving test APIs

136

- `not_answering_http_server`: Server that doesn't respond (for timeout testing)

137

- `result_getter`: Parameterized fixture for testing both .result() and .response() methods

138

139

#### IntegrationTestingFixturesMixin

140

141

Mixin class providing common fixtures and utilities for integration tests.

142

143

```python { .api }

144

class IntegrationTestingFixturesMixin:

145

http_client: HttpClient

146

http_client_type: Type[HttpClient]

147

http_future_adapter_type: Type[FutureAdapter]

148

connection_errors_exceptions: Set[Exception]

149

150

@classmethod

151

def setup_class(cls): ...

152

153

@pytest.fixture

154

def swagger_client(self) -> SwaggerClient: ...

155

156

def encode_expected_response(self, expected_response: dict) -> bytes: ...

157

```

158

159

**Class Attributes:**

160

- `http_client`: HTTP client instance for testing

161

- `http_client_type`: Type of HTTP client being tested

162

- `http_future_adapter_type`: Type of future adapter being tested

163

- `connection_errors_exceptions`: Set of connection error exception types

164

165

**Methods:**

166

- `setup_class()`: Class-level setup for test configuration

167

- `swagger_client()`: Fixture that creates SwaggerClient instances

168

- `encode_expected_response()`: Encode expected response data

169

170

#### IntegrationTestsBaseClass

171

172

Base class with comprehensive integration tests that can be inherited by HTTP client implementations.

173

174

```python { .api }

175

class IntegrationTestsBaseClass(IntegrationTestingFixturesMixin):

176

# Multiple test methods for various scenarios:

177

# - Basic API operations

178

# - Error handling (4xx, 5xx status codes)

179

# - Timeout behavior

180

# - Connection error handling

181

# - Authentication testing

182

# - Request/response validation

183

# - Fallback result behavior

184

```

185

186

This class provides a complete test suite that verifies HTTP client behavior across various scenarios.

187

188

## Usage Patterns

189

190

### Unit Testing with Mocks

191

192

```python

193

import pytest

194

from unittest.mock import patch

195

from bravado.testing.response_mocks import BravadoResponseMock

196

197

class TestPetService:

198

def setup_method(self):

199

self.pet_service = PetService() # Your service that uses bravado

200

201

@patch('your_module.swagger_client.pet.getPetById')

202

def test_get_pet_success(self, mock_get_pet):

203

# Setup mock response

204

expected_pet = {'id': 1, 'name': 'Fluffy', 'status': 'available'}

205

mock_response = BravadoResponseMock(expected_pet)

206

mock_get_pet.return_value = mock_response

207

208

# Test your service

209

pet = self.pet_service.get_pet(1)

210

211

# Assertions

212

assert pet['name'] == 'Fluffy'

213

mock_get_pet.assert_called_once_with(petId=1)

214

215

@patch('your_module.swagger_client.pet.getPetById')

216

def test_get_pet_with_fallback(self, mock_get_pet):

217

# Setup fallback mock

218

from bravado.testing.response_mocks import FallbackResultBravadoResponseMock

219

fallback_mock = FallbackResultBravadoResponseMock()

220

mock_get_pet.return_value = fallback_mock

221

222

# Test fallback behavior

223

pet = self.pet_service.get_pet_with_fallback(1)

224

225

assert pet['name'] == 'Unknown' # Your fallback data

226

assert pet['status'] == 'unavailable'

227

```

228

229

### Integration Testing with RequestsClient

230

231

```python

232

import pytest

233

from bravado.testing.integration_test import IntegrationTestsBaseClass

234

from bravado.requests_client import RequestsClient, RequestsFutureAdapter

235

236

class TestRequestsClientIntegration(IntegrationTestsBaseClass):

237

"""Integration tests for RequestsClient."""

238

239

@classmethod

240

def setup_class(cls):

241

cls.http_client_type = RequestsClient

242

cls.http_future_adapter_type = RequestsFutureAdapter

243

cls.connection_errors_exceptions = {ConnectionError}

244

super().setup_class()

245

246

def test_custom_behavior(self, swagger_client):

247

"""Test specific to RequestsClient behavior."""

248

response = swagger_client.pet.getPetById(petId=1).response()

249

assert response.result['name'] == 'doggie'

250

assert response.metadata.status_code == 200

251

```

252

253

### Integration Testing with FidoClient

254

255

```python

256

import pytest

257

from bravado.testing.integration_test import IntegrationTestsBaseClass

258

from bravado.fido_client import FidoClient, FidoFutureAdapter

259

import twisted.internet.error

260

261

class TestFidoClientIntegration(IntegrationTestsBaseClass):

262

"""Integration tests for FidoClient."""

263

264

@classmethod

265

def setup_class(cls):

266

cls.http_client_type = FidoClient

267

cls.http_future_adapter_type = FidoFutureAdapter

268

cls.connection_errors_exceptions = {

269

twisted.internet.error.ConnectionRefusedError,

270

twisted.internet.error.DNSLookupError

271

}

272

super().setup_class()

273

274

def test_async_behavior(self, swagger_client):

275

"""Test async-specific behavior."""

276

future = swagger_client.pet.getPetById(petId=1)

277

response = future.response() # This integrates with Twisted

278

assert response.result['name'] == 'doggie'

279

```

280

281

### Custom Test Server

282

283

```python

284

import bottle

285

import threading

286

import time

287

from bravado.testing.integration_test import _class_fqn

288

289

def create_test_server():

290

"""Create custom test server for your API."""

291

app = bottle.Bottle()

292

293

@app.route('/pets/<pet_id:int>', method='GET')

294

def get_pet(pet_id):

295

if pet_id == 404:

296

bottle.abort(404, "Pet not found")

297

return {

298

'id': pet_id,

299

'name': f'Pet {pet_id}',

300

'status': 'available'

301

}

302

303

@app.route('/pets', method='POST')

304

def create_pet():

305

pet_data = bottle.request.json

306

pet_data['id'] = 123 # Simulate ID assignment

307

return pet_data

308

309

return app

310

311

class TestWithCustomServer:

312

@pytest.fixture(scope='class')

313

def test_server(self):

314

"""Custom test server fixture."""

315

app = create_test_server()

316

317

# Start server in thread

318

server_thread = threading.Thread(

319

target=lambda: app.run(host='localhost', port=5000, quiet=True)

320

)

321

server_thread.daemon = True

322

server_thread.start()

323

time.sleep(0.1) # Wait for server to start

324

325

yield 'http://localhost:5000'

326

327

def test_custom_api(self, test_server):

328

from bravado.client import SwaggerClient

329

330

# You would need to provide your own swagger spec for the custom server

331

# This is just an example structure

332

spec_dict = {

333

'swagger': '2.0',

334

'info': {'title': 'Test API', 'version': '1.0'},

335

'host': 'localhost:5000',

336

'paths': {

337

'/pets/{petId}': {

338

'get': {

339

'operationId': 'getPetById',

340

'parameters': [

341

{'name': 'petId', 'in': 'path', 'type': 'integer', 'required': True}

342

],

343

'responses': {'200': {'description': 'Success'}}

344

}

345

}

346

}

347

}

348

349

client = SwaggerClient.from_spec(spec_dict, origin_url=test_server)

350

response = client.pet.getPetById(petId=1).response()

351

assert response.result['name'] == 'Pet 1'

352

```

353

354

### Testing Error Scenarios

355

356

```python

357

import pytest

358

from bravado.testing.response_mocks import FallbackResultBravadoResponseMock

359

from bravado.exception import HTTPNotFound, BravadoTimeoutError

360

361

class TestErrorHandling:

362

def test_http_404_handling(self):

363

"""Test handling of HTTP 404 errors."""

364

# Mock 404 response

365

from bravado.testing.response_mocks import IncomingResponseMock

366

367

mock_response = IncomingResponseMock(

368

status_code=404,

369

text='{"error": "Pet not found"}',

370

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

371

)

372

373

# Your error handling logic would go here

374

assert mock_response.status_code == 404

375

376

def test_timeout_with_fallback(self):

377

"""Test timeout handling with fallback results."""

378

fallback_mock = FallbackResultBravadoResponseMock(

379

exception=BravadoTimeoutError("Connection timeout")

380

)

381

382

fallback_data = {'error': 'Service temporarily unavailable'}

383

response = fallback_mock(fallback_result=fallback_data)

384

385

assert response.result == fallback_data

386

assert response.metadata.is_fallback_result is True

387

```

388

389

## Test Data Constants

390

391

The testing module provides predefined test data for integration tests:

392

393

```python { .api }

394

ROUTE_1_RESPONSE: dict # Sample API response data

395

ROUTE_2_RESPONSE: dict # Alternative response data

396

API_RESPONSE: dict # Complete API response structure

397

SWAGGER_SPEC_DICT: dict # Sample Swagger specification

398

```

399

400

These constants provide consistent test data across different test scenarios.

401

402

## Best Practices

403

404

1. **Use Mocks for Unit Tests**: Test your business logic without making real HTTP calls

405

2. **Use Integration Tests for HTTP Clients**: Verify actual HTTP client behavior

406

3. **Test Error Scenarios**: Include tests for timeouts, connection errors, and HTTP errors

407

4. **Test Fallback Behavior**: Verify fallback results work as expected

408

5. **Parameterize Tests**: Test both `.result()` and `.response()` methods

409

6. **Mock External Dependencies**: Don't make real API calls in tests

410

411

```python

412

# Good testing example

413

import pytest

414

from unittest.mock import patch, MagicMock

415

from bravado.testing.response_mocks import BravadoResponseMock, FallbackResultBravadoResponseMock

416

417

class TestPetService:

418

@pytest.fixture

419

def pet_service(self):

420

return PetService() # Your service class

421

422

@pytest.fixture

423

def mock_client(self):

424

"""Mock SwaggerClient for testing."""

425

client = MagicMock()

426

return client

427

428

def test_get_pet_success(self, pet_service, mock_client):

429

"""Test successful pet retrieval."""

430

# Setup

431

expected_pet = {'id': 1, 'name': 'Fluffy', 'status': 'available'}

432

mock_response = BravadoResponseMock(expected_pet)

433

mock_client.pet.getPetById.return_value = mock_response

434

435

pet_service.client = mock_client

436

437

# Execute

438

result = pet_service.get_pet(1)

439

440

# Verify

441

assert result['name'] == 'Fluffy'

442

mock_client.pet.getPetById.assert_called_once_with(petId=1)

443

444

def test_get_pet_with_timeout_fallback(self, pet_service, mock_client):

445

"""Test fallback behavior on timeout."""

446

# Setup fallback mock

447

fallback_mock = FallbackResultBravadoResponseMock()

448

mock_client.pet.getPetById.return_value = fallback_mock

449

450

pet_service.client = mock_client

451

452

# Execute with fallback

453

result = pet_service.get_pet_with_fallback(1)

454

455

# Verify fallback was used

456

assert result['name'] == 'Unknown Pet'

457

assert result['status'] == 'unavailable'

458

459

@pytest.mark.parametrize("status_code,expected_error", [

460

(404, HTTPNotFound),

461

(401, HTTPUnauthorized),

462

(500, HTTPInternalServerError)

463

])

464

def test_get_pet_http_errors(self, pet_service, mock_client, status_code, expected_error):

465

"""Test various HTTP error scenarios."""

466

# Setup error mock

467

mock_client.pet.getPetById.side_effect = expected_error(

468

response=MagicMock(status_code=status_code)

469

)

470

471

pet_service.client = mock_client

472

473

# Execute and verify error

474

with pytest.raises(expected_error):

475

pet_service.get_pet(1)

476

```