or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

execution.mdindex.mditerator-dict.mdmetaclass.mdmoves.mdstring-bytes.mdtesting.mdversion-detection.md

testing.mddocs/

0

# Testing Utilities

1

2

Utilities for writing tests that work across Python versions, including assertion method compatibility. These functions provide unified interfaces for test assertions that handle the method name differences between Python 2 and 3 unittest modules.

3

4

## Capabilities

5

6

### Assertion Method Compatibility

7

8

Functions that provide consistent assertion methods across Python versions by wrapping the appropriate unittest methods.

9

10

```python { .api }

11

def assertCountEqual(self, *args, **kwargs) -> None

12

"""Assert that two iterables have the same elements regardless of order."""

13

14

def assertRaisesRegex(self, *args, **kwargs) -> ContextManager

15

"""Assert that an exception is raised and its message matches a regex pattern."""

16

17

def assertRegex(self, *args, **kwargs) -> None

18

"""Assert that a string matches a regular expression pattern."""

19

20

def assertNotRegex(self, *args, **kwargs) -> None

21

"""Assert that a string does not match a regular expression pattern."""

22

```

23

24

**Note:** These functions are wrappers that delegate to the appropriate unittest method based on Python version, using the correct method names (`assertItemsEqual`/`assertCountEqual`, `assertRaisesRegexp`/`assertRaisesRegex`, etc.). They accept the same arguments as the underlying unittest methods.

25

26

**Usage Examples:**

27

28

```python

29

import six

30

import unittest

31

import re

32

33

class MyTestCase(unittest.TestCase):

34

35

def test_count_equal_assertion(self):

36

"""Test assertCountEqual functionality."""

37

list1 = [1, 2, 3, 2]

38

list2 = [2, 1, 3, 2]

39

40

# Use six.assertCountEqual for cross-version compatibility

41

six.assertCountEqual(self, list1, list2)

42

43

# This assertion would fail

44

with self.assertRaises(AssertionError):

45

six.assertCountEqual(self, [1, 2, 3], [1, 2, 3, 4])

46

47

def test_regex_assertions(self):

48

"""Test regex-based assertions."""

49

text = "Hello, World! This is a test message."

50

51

# Assert text matches pattern

52

six.assertRegex(self, text, r"Hello.*World")

53

six.assertRegex(self, text, re.compile(r"\w+\s+\w+"))

54

55

# Assert text does not match pattern

56

six.assertNotRegex(self, text, r"goodbye")

57

six.assertNotRegex(self, text, re.compile(r"\d+"))

58

59

def test_exception_with_regex(self):

60

"""Test exception raising with regex matching."""

61

62

def problematic_function():

63

raise ValueError("Invalid input: expected number, got string")

64

65

# Assert exception is raised with matching message

66

with six.assertRaisesRegex(self, ValueError, r"Invalid input.*expected"):

67

problematic_function()

68

69

# Using compiled regex

70

pattern = re.compile(r"expected \w+, got \w+")

71

with six.assertRaisesRegex(self, ValueError, pattern):

72

problematic_function()

73

74

if __name__ == '__main__':

75

unittest.main()

76

```

77

78

## Assertion Method Constants

79

80

String constants that provide the correct method names for different Python versions.

81

82

```python { .api }

83

_assertCountEqual: str # Method name for count equal assertion

84

_assertRaisesRegex: str # Method name for raises regex assertion

85

_assertRegex: str # Method name for regex assertion

86

_assertNotRegex: str # Method name for not regex assertion

87

```

88

89

These constants contain the appropriate method names:

90

- Python 2: `assertItemsEqual`, `assertRaisesRegexp`, `assertRegexpMatches`, `assertNotRegexpMatches`

91

- Python 3: `assertCountEqual`, `assertRaisesRegex`, `assertRegex`, `assertNotRegex`

92

93

**Usage Example:**

94

95

```python

96

import six

97

import unittest

98

99

class MyTestCase(unittest.TestCase):

100

101

def test_using_constants(self):

102

"""Example of using method name constants directly."""

103

104

# Get the appropriate method for the current Python version

105

count_equal_method = getattr(self, six._assertCountEqual)

106

107

# Use the method

108

count_equal_method([1, 2, 3], [3, 2, 1])

109

110

# Similarly for regex assertions

111

regex_method = getattr(self, six._assertRegex)

112

regex_method("hello world", r"hello.*world")

113

```

114

115

## Advanced Testing Patterns

116

117

### Custom Test Base Class

118

119

```python

120

import six

121

import unittest

122

123

class CrossVersionTestCase(unittest.TestCase):

124

"""Base test case with cross-version assertion helpers."""

125

126

def assertCountEqual(self, first, second, msg=None):

127

"""Wrapper for assertCountEqual that works across versions."""

128

return six.assertCountEqual(self, first, second, msg)

129

130

def assertRaisesRegex(self, expected_exception, expected_regex):

131

"""Wrapper for assertRaisesRegex that works across versions."""

132

return six.assertRaisesRegex(self, expected_exception, expected_regex)

133

134

def assertRegex(self, text, expected_regex, msg=None):

135

"""Wrapper for assertRegex that works across versions."""

136

return six.assertRegex(self, text, expected_regex, msg)

137

138

def assertNotRegex(self, text, unexpected_regex, msg=None):

139

"""Wrapper for assertNotRegex that works across versions."""

140

return six.assertNotRegex(self, text, unexpected_regex, msg)

141

142

def assertStringTypes(self, value, msg=None):

143

"""Assert that value is a string type (works across versions)."""

144

self.assertIsInstance(value, six.string_types, msg)

145

146

def assertTextType(self, value, msg=None):

147

"""Assert that value is a text type (unicode/str)."""

148

self.assertIsInstance(value, six.text_type, msg)

149

150

def assertBinaryType(self, value, msg=None):

151

"""Assert that value is a binary type (bytes/str)."""

152

self.assertIsInstance(value, six.binary_type, msg)

153

154

# Usage example

155

class StringProcessorTest(CrossVersionTestCase):

156

157

def test_string_processing(self):

158

"""Test string processing functionality."""

159

from mymodule import process_string

160

161

result = process_string("hello")

162

163

# Use cross-version assertions

164

self.assertStringTypes(result)

165

self.assertRegex(result, r"^processed:")

166

167

# Test with unicode

168

unicode_input = six.u("héllo")

169

unicode_result = process_string(unicode_input)

170

self.assertTextType(unicode_result)

171

```

172

173

### Parameterized Testing with Version Checks

174

175

```python

176

import six

177

import unittest

178

179

class VersionAwareTest(unittest.TestCase):

180

"""Test class that adapts behavior based on Python version."""

181

182

def setUp(self):

183

"""Set up test fixtures based on Python version."""

184

if six.PY2:

185

self.string_type = unicode

186

self.binary_type = str

187

else:

188

self.string_type = str

189

self.binary_type = bytes

190

191

def test_string_handling(self):

192

"""Test that varies behavior by Python version."""

193

test_data = [

194

("hello", "HELLO"),

195

(six.u("wörld"), six.u("WÖRLD")),

196

]

197

198

for input_val, expected in test_data:

199

with self.subTest(input=input_val):

200

result = input_val.upper()

201

self.assertEqual(result, expected)

202

self.assertIsInstance(result, self.string_type)

203

204

@unittest.skipUnless(six.PY3, "Python 3 only test")

205

def test_python3_feature(self):

206

"""Test that only runs on Python 3."""

207

# Test Python 3 specific functionality

208

self.assertRegex("test string", r"test.*string")

209

210

@unittest.skipUnless(six.PY2, "Python 2 only test")

211

def test_python2_feature(self):

212

"""Test that only runs on Python 2."""

213

# Test Python 2 specific functionality

214

self.assertRegexpMatches("test string", r"test.*string")

215

216

# Decorator for version-specific tests

217

def py2_only(func):

218

"""Decorator to skip test on Python 3."""

219

return unittest.skipUnless(six.PY2, "Python 2 only")(func)

220

221

def py3_only(func):

222

"""Decorator to skip test on Python 2."""

223

return unittest.skipUnless(six.PY3, "Python 3 only")(func)

224

225

class MyFeatureTest(unittest.TestCase):

226

227

@py2_only

228

def test_legacy_behavior(self):

229

"""Test legacy behavior specific to Python 2."""

230

pass

231

232

@py3_only

233

def test_modern_behavior(self):

234

"""Test modern behavior specific to Python 3."""

235

pass

236

```

237

238

### Mock and Patch Utilities

239

240

```python

241

import six

242

import unittest

243

244

try:

245

from unittest.mock import Mock, patch, MagicMock

246

except ImportError:

247

# Python 2 fallback

248

from mock import Mock, patch, MagicMock

249

250

class MockingTest(unittest.TestCase):

251

"""Example of version-aware mocking."""

252

253

def test_mocked_function(self):

254

"""Test with mocked function using six utilities."""

255

256

with patch('mymodule.some_function') as mock_func:

257

mock_func.return_value = six.u("mocked result")

258

259

from mymodule import call_some_function

260

result = call_some_function()

261

262

# Verify the result using six assertions

263

six.assertRegex(self, result, r"mocked.*result")

264

mock_func.assert_called_once()

265

266

def test_string_type_handling(self):

267

"""Test mocking with proper string type handling."""

268

269

mock_obj = Mock()

270

mock_obj.get_data.return_value = six.ensure_text("test data")

271

272

result = mock_obj.get_data()

273

274

# Verify result is proper text type

275

self.assertIsInstance(result, six.text_type)

276

six.assertRegex(self, result, r"test.*data")

277

278

# Test runner helper

279

def run_cross_version_tests():

280

"""Helper to run tests with version information."""

281

import sys

282

283

six.print_(f"Running tests on Python {sys.version}")

284

six.print_(f"Six version: {six.__version__}")

285

six.print_(f"PY2: {six.PY2}, PY3: {six.PY3}")

286

287

# Discover and run tests

288

loader = unittest.TestLoader()

289

suite = loader.discover('.')

290

runner = unittest.TextTestRunner(verbosity=2)

291

result = runner.run(suite)

292

293

return result.wasSuccessful()

294

295

if __name__ == '__main__':

296

success = run_cross_version_tests()

297

sys.exit(0 if success else 1)

298

```

299

300

## Integration with Testing Frameworks

301

302

### pytest Integration

303

304

```python

305

import six

306

import pytest

307

308

class TestSixIntegration:

309

"""pytest tests using six utilities."""

310

311

def test_assertion_methods(self):

312

"""Test six assertion methods with pytest."""

313

314

# Note: six assertion methods expect unittest.TestCase self

315

# Create a minimal test case instance

316

import unittest

317

test_case = unittest.TestCase()

318

319

# Use six assertions

320

six.assertCountEqual(test_case, [1, 2, 3], [3, 2, 1])

321

six.assertRegex(test_case, "hello world", r"hello.*world")

322

323

with pytest.raises(AssertionError):

324

six.assertCountEqual(test_case, [1, 2], [1, 2, 3])

325

326

@pytest.mark.skipif(not six.PY3, reason="Python 3 only")

327

def test_py3_specific(self):

328

"""Test that only runs on Python 3."""

329

assert six.PY3

330

assert not six.PY2

331

332

def test_string_types(self):

333

"""Test string type checking with pytest."""

334

test_string = "hello"

335

assert isinstance(test_string, six.string_types)

336

337

if six.PY2:

338

unicode_string = six.u("hello")

339

assert isinstance(unicode_string, six.text_type)

340

```

341

342

This comprehensive testing utilities documentation provides developers with all the tools they need to write cross-version compatible tests using the six library.