testtools-dev team mailing list archive
-
testtools-dev team
-
Mailing list archive
-
Message #00532
[Merge] lp:~abentley/testtools/expected-exception into lp:testtools
Aaron Bentley has proposed merging lp:~abentley/testtools/expected-exception into lp:testtools.
Requested reviews:
Jonathan Lange (jml)
For more details, see:
https://code.launchpad.net/~abentley/testtools/expected-exception/+merge/46858
This introduces the ExpectedException context manager for nicer error handling.
The tests are split into a separate file because they use the with statement.
The exec line is used because future imports cannot be conditionally imported.
--
https://code.launchpad.net/~abentley/testtools/expected-exception/+merge/46858
Your team testtools developers is subscribed to branch lp:testtools.
=== modified file 'testtools/__init__.py'
--- testtools/__init__.py 2010-12-18 07:21:34 +0000
+++ testtools/__init__.py 2011-01-20 00:09:53 +0000
@@ -37,6 +37,7 @@
)
from testtools.testcase import (
ErrorHolder,
+ ExpectedException,
PlaceHolder,
TestCase,
clone_test_with_new_id,
=== modified file 'testtools/testcase.py'
--- testtools/testcase.py 2011-01-13 22:32:02 +0000
+++ testtools/testcase.py 2011-01-20 00:09:53 +0000
@@ -14,6 +14,7 @@
import copy
import itertools
+import re
import sys
import types
import unittest
@@ -682,3 +683,24 @@
def _id(obj):
return obj
return _id
+
+
+class ExpectedException:
+ """A context manager to handle expected exceptions."""
+
+ def __init__(self, exc_type, value_re):
+ self.exc_type = exc_type
+ self.value_re = value_re
+
+ def __enter__(self):
+ pass
+
+ def __exit__(self, exc_type, exc_value, traceback):
+ if exc_type is None:
+ raise AssertionError('%s not raised.' % self.exc_type.__name__)
+ if exc_type != self.exc_type:
+ return False
+ if not re.match(self.value_re, str(exc_value)):
+ raise AssertionError('"%s" does not match "%s".' %
+ (str(exc_value), self.value_re))
+ return True
=== modified file 'testtools/tests/test_testtools.py'
--- testtools/tests/test_testtools.py 2010-12-13 01:15:11 +0000
+++ testtools/tests/test_testtools.py 2011-01-20 00:09:53 +0000
@@ -30,6 +30,12 @@
Python27TestResult,
ExtendedTestResult,
)
+try:
+ exec('from __future__ import with_statement')
+except SyntaxError:
+ pass
+else:
+ from test_with_with import *
class TestPlaceHolder(TestCase):
=== added file 'testtools/tests/test_with_with.py'
--- testtools/tests/test_with_with.py 1970-01-01 00:00:00 +0000
+++ testtools/tests/test_with_with.py 2011-01-20 00:09:53 +0000
@@ -0,0 +1,40 @@
+from __future__ import with_statement
+
+from testtools import (
+ ExpectedException,
+ TestCase,
+ )
+
+class TestExpectedException(TestCase):
+ """Test the ExpectedException context manager."""
+
+ def test_pass_on_raise(self):
+ with ExpectedException(ValueError, 'tes.'):
+ raise ValueError('test')
+
+ def test_raise_on_text_mismatch(self):
+ try:
+ with ExpectedException(ValueError, 'tes.'):
+ raise ValueError('mismatch')
+ except AssertionError, e:
+ self.assertEqual('"mismatch" does not match "tes.".', str(e))
+ else:
+ self.fail('AssertionError not raised.')
+
+ def test_raise_on_error_mismatch(self):
+ try:
+ with ExpectedException(TypeError, 'tes.'):
+ raise ValueError('mismatch')
+ except ValueError, e:
+ self.assertEqual('mismatch', str(e))
+ else:
+ self.fail('ValueError not raised.')
+
+ def test_raise_if_no_exception(self):
+ try:
+ with ExpectedException(TypeError, 'tes.'):
+ pass
+ except AssertionError, e:
+ self.assertEqual('TypeError not raised.', str(e))
+ else:
+ self.fail('AssertionError not raised.')
Follow ups