or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

analysis-reporting.mdaspect-benchmarking.mdcli-tools.mdconfiguration.mdcore-benchmarking.mdindex.mdstorage-comparison.md

aspect-benchmarking.mddocs/

0

# Aspect-Oriented Benchmarking

1

2

## Overview

3

4

Aspect-oriented benchmarking allows you to benchmark existing functions without modifying the test code structure. This is useful for benchmarking third-party libraries, existing functions, or when you want to benchmark multiple function calls within a single test.

5

6

## Core APIs

7

8

### BenchmarkFixture.weave

9

10

```python { .api }

11

def weave(self, target, **kwargs) -> None:

12

"""

13

Apply benchmarking to a target function using aspect-oriented programming.

14

15

Args:

16

target: The function, method, or object to benchmark

17

**kwargs: Additional arguments passed to aspectlib.weave()

18

19

Raises:

20

ImportError: If aspectlib is not installed

21

FixtureAlreadyUsed: If the fixture has already been used in this test

22

"""

23

```

24

25

### BenchmarkFixture.patch

26

27

```python { .api }

28

def patch(self, target, **kwargs) -> None:

29

"""

30

Alias for weave method - applies benchmarking to target function.

31

32

Args:

33

target: The function, method, or object to benchmark

34

**kwargs: Additional arguments passed to aspectlib.weave()

35

36

Raises:

37

ImportError: If aspectlib is not installed

38

FixtureAlreadyUsed: If the fixture has already been used in this test

39

"""

40

```

41

42

### benchmark_weave fixture

43

44

```python { .api }

45

@pytest.fixture

46

def benchmark_weave(benchmark) -> callable:

47

"""

48

Shortcut fixture that provides direct access to benchmark.weave.

49

50

Returns:

51

callable: The benchmark.weave method

52

"""

53

```

54

55

## Installation Requirements

56

57

Aspect-oriented benchmarking requires the `aspectlib` package:

58

59

```bash

60

pip install pytest-benchmark[aspect]

61

# or

62

pip install aspectlib

63

```

64

65

## Usage Examples

66

67

### Basic Function Weaving

68

69

```python

70

import math

71

72

def test_math_operations(benchmark):

73

# Benchmark all calls to math.sqrt in this test

74

benchmark.weave(math.sqrt)

75

76

# Now all calls to math.sqrt will be benchmarked

77

result1 = math.sqrt(16)

78

result2 = math.sqrt(25)

79

result3 = math.sqrt(36)

80

81

assert result1 == 4.0

82

assert result2 == 5.0

83

assert result3 == 6.0

84

```

85

86

### Benchmarking Class Methods

87

88

```python

89

class DataProcessor:

90

def process(self, data):

91

return sum(x**2 for x in data)

92

93

def transform(self, data):

94

return [x * 2 for x in data]

95

96

def test_class_method_weaving(benchmark):

97

processor = DataProcessor()

98

99

# Benchmark the process method

100

benchmark.weave(processor, 'process')

101

102

data = list(range(1000))

103

result = processor.process(data)

104

105

assert result == sum(x**2 for x in range(1000))

106

```

107

108

### Using benchmark_weave Fixture

109

110

```python

111

def test_with_weave_fixture(benchmark_weave):

112

import json

113

114

# Direct access to weave functionality

115

benchmark_weave(json.dumps)

116

117

data = {"key": "value", "numbers": [1, 2, 3, 4, 5]}

118

result = json.dumps(data)

119

120

assert '"key": "value"' in result

121

```

122

123

### Weaving Multiple Functions

124

125

```python

126

def custom_function(x):

127

return x * 2 + 1

128

129

def another_function(x, y):

130

return x + y

131

132

def test_multiple_weaving(benchmark):

133

# Note: Only one weave per fixture instance

134

# This will benchmark the first function called

135

benchmark.weave(custom_function)

136

137

result1 = custom_function(5) # This gets benchmarked

138

result2 = another_function(3, 4) # This doesn't

139

140

assert result1 == 11

141

assert result2 == 7

142

```

143

144

### Advanced Weaving with aspectlib Options

145

146

```python

147

def test_advanced_weaving(benchmark):

148

def target_function(a, b, c=10):

149

return a + b + c

150

151

# Pass additional options to aspectlib.weave

152

benchmark.weave(

153

target_function,

154

# aspectlib options

155

lazy=True, # Lazy weaving

156

# methods=['__call__'] # Specific methods to weave

157

)

158

159

result = target_function(1, 2, c=3)

160

assert result == 6

161

```

162

163

## Weaving Patterns

164

165

### Library Function Benchmarking

166

167

```python

168

import hashlib

169

170

def test_hashlib_performance(benchmark):

171

benchmark.weave(hashlib.md5)

172

173

data = b"Hello, World!" * 1000

174

175

# All md5() calls in this test will be benchmarked

176

hash1 = hashlib.md5(data)

177

hash2 = hashlib.md5(data)

178

179

assert hash1.hexdigest() == hash2.hexdigest()

180

```

181

182

### Method Interception

183

184

```python

185

class DatabaseConnection:

186

def __init__(self):

187

self.queries = []

188

189

def execute(self, query):

190

self.queries.append(query)

191

return f"Result for: {query}"

192

193

def test_database_method_weaving(benchmark):

194

db = DatabaseConnection()

195

196

# Benchmark the execute method

197

benchmark.weave(db.execute)

198

199

# Multiple calls - all benchmarked as one aggregate

200

results = []

201

results.append(db.execute("SELECT * FROM users"))

202

results.append(db.execute("SELECT * FROM products"))

203

results.append(db.execute("SELECT * FROM orders"))

204

205

assert len(results) == 3

206

assert len(db.queries) == 3

207

```

208

209

### Module-Level Function Weaving

210

211

```python

212

# mymodule.py content (example)

213

def expensive_computation(n):

214

return sum(i**2 for i in range(n))

215

216

# Test file

217

def test_module_function_weaving(benchmark):

218

import mymodule

219

220

# Weave the module function

221

benchmark.weave(mymodule.expensive_computation)

222

223

result = mymodule.expensive_computation(1000)

224

expected = sum(i**2 for i in range(1000))

225

assert result == expected

226

```

227

228

## Limitations and Considerations

229

230

### Single Use Constraint

231

232

```python

233

def test_weave_single_use(benchmark):

234

def func1():

235

return 1

236

237

def func2():

238

return 2

239

240

# This works

241

benchmark.weave(func1)

242

result1 = func1()

243

244

# This would raise FixtureAlreadyUsed

245

# benchmark.weave(func2) # Error!

246

```

247

248

### Cleanup Behavior

249

250

The weaving is automatically cleaned up after the test completes. No manual cleanup is required.

251

252

```python

253

def test_automatic_cleanup(benchmark):

254

import math

255

256

original_sqrt = math.sqrt

257

benchmark.weave(math.sqrt)

258

259

# Function is woven during test

260

result = math.sqrt(16)

261

assert result == 4.0

262

263

# After test completes, weaving is automatically removed

264

```

265

266

### Error Handling

267

268

```python

269

def test_weave_error_handling(benchmark):

270

def failing_function():

271

raise ValueError("Test error")

272

273

benchmark.weave(failing_function)

274

275

# Exceptions are properly propagated

276

with pytest.raises(ValueError):

277

failing_function()

278

279

# Benchmark still captures error state

280

assert benchmark.has_error

281

```

282

283

## Integration with Test Frameworks

284

285

### Compatibility with Mock Libraries

286

287

```python

288

from unittest.mock import patch, MagicMock

289

290

def test_weave_with_mocks(benchmark):

291

with patch('requests.get') as mock_get:

292

mock_get.return_value = MagicMock(status_code=200)

293

294

# Can weave mocked functions

295

benchmark.weave(mock_get)

296

297

import requests

298

response = requests.get('http://example.com')

299

300

assert response.status_code == 200

301

mock_get.assert_called_once()

302

```

303

304

### Fixture Interaction

305

306

```python

307

@pytest.fixture

308

def sample_data():

309

return list(range(1000))

310

311

def test_weave_with_fixtures(benchmark, sample_data):

312

def process_data(data):

313

return sum(x**2 for x in data)

314

315

benchmark.weave(process_data)

316

317

result = process_data(sample_data)

318

expected = sum(x**2 for x in range(1000))

319

assert result == expected

320

```