← Back to team overview

testtools-dev team mailing list archive

[Merge] lp:~jml/testtools/assert-raises-lambda into lp:testtools

 

Jonathan Lange has proposed merging lp:~jml/testtools/assert-raises-lambda into lp:testtools.

Requested reviews:
  testtools committers (testtools-committers)
Related bugs:
  Bug #881052 in testtools: "assertRaises gives error about a lambda"
  https://bugs.launchpad.net/testtools/+bug/881052

For more details, see:
https://code.launchpad.net/~jml/testtools/assert-raises-lambda/+merge/90574

When assertRaises currently fails, it doesn't mention the callable that it was invoked with.  Instead it mentions a lambda that we make up in order to be able to re-use the Raises matcher.

This patch addresses this problem by using a wrapper object instead of a lambda.  The wrapper object is a nullary callable and has a custom __repr__ method that forwards to the callable that assertRaises was invoked with.


-- 
https://code.launchpad.net/~jml/testtools/assert-raises-lambda/+merge/90574
Your team testtools developers is subscribed to branch lp:testtools.
=== modified file 'NEWS'
--- NEWS	2012-01-10 17:59:27 +0000
+++ NEWS	2012-01-28 13:49:24 +0000
@@ -21,6 +21,9 @@
   previous release promised clean stack, but now we actually provide it.
   (Jonathan Lange, #854769)
 
+* ``assertRaises`` now includes the ``repr`` of the callable that failed to raise
+  properly. (Jonathan Lange, #881052)
+
 * Failed equality assertions now line up. (Jonathan Lange, #879339)
 
 * ``MatchesAll`` and ``MatchesListwise`` both take a ``first_only`` keyword

=== modified file 'testtools/testcase.py'
--- testtools/testcase.py	2011-12-05 15:21:33 +0000
+++ testtools/testcase.py	2012-01-28 13:49:24 +0000
@@ -384,8 +384,13 @@
         capture = CaptureMatchee()
         matcher = Raises(MatchesAll(ReRaiseOtherTypes(),
                 MatchesException(excClass), capture))
-
-        self.assertThat(lambda: callableObj(*args, **kwargs), matcher)
+        class OurCallable(object):
+            """Wrapper around callableObj to ensure good repr."""
+            def __call__(self):
+                return callableObj(*args, **kwargs)
+            def __repr__(self):
+                return repr(callableObj)
+        self.assertThat(OurCallable(), matcher)
         return capture.matchee
     failUnlessRaises = assertRaises
 

=== modified file 'testtools/tests/test_testcase.py'
--- testtools/tests/test_testcase.py	2011-10-30 16:27:05 +0000
+++ testtools/tests/test_testcase.py	2012-01-28 13:49:24 +0000
@@ -25,6 +25,7 @@
     )
 from testtools.matchers import (
     Annotate,
+    Contains,
     DocTestMatches,
     Equals,
     MatchesException,
@@ -309,6 +310,17 @@
         self.assertFails('<function <lambda> at ...> returned None',
             self.assertRaises, expectedExceptions, lambda: None)
 
+    def test_assertRaises_function_repr_in_exception(self):
+        # When assertRaises fails, it includes the repr of the invoked
+        # function in the error message, so it's easy to locate the problem.
+        def foo():
+            """An arbitrary function."""
+            pass
+        self.assertThat(
+            lambda: self.assertRaises(Exception, foo),
+            Raises(
+                MatchesException(self.failureException, '.*%r.*' % (foo,))))
+
     def assertFails(self, message, function, *args, **kwargs):
         """Assert that function raises a failure with the given message."""
         failure = self.assertRaises(


Follow ups