Merge lp:~lifeless/testtools/matchers into lp:~testtools-committers/testtools/trunk

Proposed by Robert Collins
Status: Merged
Merged at revision: 226
Proposed branch: lp:~lifeless/testtools/matchers
Merge into: lp:~testtools-committers/testtools/trunk
Diff against target: 602 lines (+219/-65)
6 files modified
NEWS (+8/-0)
doc/for-test-authors.rst (+26/-0)
testtools/matchers.py (+84/-4)
testtools/testcase.py (+38/-37)
testtools/tests/test_matchers.py (+36/-0)
testtools/tests/test_testcase.py (+27/-24)
To merge this branch: bzr merge lp:~lifeless/testtools/matchers
Reviewer Review Type Date Requested Status
Jonathan Lange Needs Fixing
Review via email: mp+71477@code.launchpad.net

Description of the change

Migrate all the implementations of assert* to be matcher based. Add additional matchers (and tweak existing ones [compatibly] as needed).

Also changed assertThat to take a message; we haven't done a release with verbose= yet, so I put the parameter in in the 'natural' place.

To post a comment you must log in.
Revision history for this message
Jonathan Lange (jml) wrote :

Thanks for doing this.

doc/for-test-authors.rst:
 * The heading for the IsInstance matcher is "Is", should be "IsInstance".

testtools/testcase.py
 * Please delete the XXX in assertThat about taking an optional message parameter.
 * The line "raise matchee[0], matchee[1], matchee[2]" is invalid syntax in Python 3. Use testtools.compat.reraise(*matchee) instead.
 * Is there a reason that expectFailure wasn't also changed?

Generally, the new failure messages for the negative assert methods (e.g. assertNotIn) are worse than the current ones. To some extent, this would be addressed by a fix for bug 704219.

Separately from this branch, I think we want to provide an In or IsIn matcher to complement Contains.

review: Needs Fixing
Revision history for this message
Robert Collins (lifeless) wrote :

On Mon, Aug 15, 2011 at 11:44 PM, Jonathan Lange <email address hidden> wrote:
> Review: Needs Fixing
> Thanks for doing this.
>
> doc/for-test-authors.rst:
>  * The heading for the IsInstance matcher is "Is", should be "IsInstance".
>
> testtools/testcase.py
>  * Please delete the XXX in assertThat about taking an optional message parameter.
>  * The line "raise matchee[0], matchee[1], matchee[2]" is invalid syntax in Python 3. Use testtools.compat.reraise(*matchee) instead.

The rest seem shallow; I will get to them at some point(ETOOMUCHON),
perhaps you would like to just fix-as-landing ?

>  * Is there a reason that expectFailure wasn't also changed?

flippantly, it didn't have a TODO; more seriously, it was complex, and
the branch was big enough, and ugly enough, that I wanted to wrap it
up.

> Generally, the new failure messages for the negative assert methods (e.g. assertNotIn) are worse than the current ones. To some extent, this would be addressed by a fix for bug 704219.

What should we do about this?

> Separately from this branch, I think we want to provide an In or IsIn matcher to complement Contains.

Yes.

-Rob

Revision history for this message
Jonathan Lange (jml) wrote :

On Mon, Aug 15, 2011 at 1:01 PM, Robert Collins
<email address hidden> wrote:
> On Mon, Aug 15, 2011 at 11:44 PM, Jonathan Lange <email address hidden> wrote:
>> Review: Needs Fixing
>> Thanks for doing this.
>>
>> doc/for-test-authors.rst:
>>  * The heading for the IsInstance matcher is "Is", should be "IsInstance".
>>
>> testtools/testcase.py
>>  * Please delete the XXX in assertThat about taking an optional message parameter.
>>  * The line "raise matchee[0], matchee[1], matchee[2]" is invalid syntax in Python 3. Use testtools.compat.reraise(*matchee) instead.
>
> The rest seem shallow; I will get to them at some point(ETOOMUCHON),
> perhaps you would like to just fix-as-landing ?
>

Am happy to do so.

>>  * Is there a reason that expectFailure wasn't also changed?
>
> flippantly, it didn't have a TODO; more seriously, it was complex, and
> the branch was big enough, and ugly enough, that I wanted to wrap it
> up.
>

Fair enough.

>> Generally, the new failure messages for the negative assert methods (e.g. assertNotIn) are worse than the current ones. To some extent, this would be addressed by a fix for bug 704219.
>
> What should we do about this?
>

Fix the bug, later.

jml

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'NEWS'
2--- NEWS 2011-08-09 13:12:39 +0000
3+++ NEWS 2011-08-14 12:18:23 +0000
4@@ -34,6 +34,9 @@
5 tells us to display. Old-style verbose output can be had by passing
6 ``verbose=True`` to assertThat. (Jonathan Lange, #675323, #593190)
7
8+* assertThat accepts a message which will be used to annotate the matcher. This
9+ can be given as a third parameter or as a keyword parameter. (Robert Collins)
10+
11 * Automated the Launchpad part of the release process.
12 (Jonathan Lange, #623486)
13
14@@ -62,6 +65,9 @@
15 * ``MatchesException`` now allows you to match exceptions against any matcher,
16 rather than just regular expressions. (Jonathan Lange, #791889)
17
18+* ``MatchesException`` now permits a tuple of types rather than a single type
19+ (when using the type matching mode). (Robert Collins)
20+
21 * ``MatchesStructure.byEquality`` added to make the common case of matching
22 many attributes by equality much easier. ``MatchesStructure.byMatcher``
23 added in case folk want to match by things other than equality.
24@@ -75,6 +81,8 @@
25 * ``AllMatch`` matches many values against a single matcher.
26 (Jonathan Lange, #615108)
27
28+ * ``Contains``. (Robert Collins)
29+
30 * ``GreaterThan``. (Christian Kampka)
31
32 * New helper, ``safe_hasattr`` added. (Jonathan Lange)
33
34=== modified file 'doc/for-test-authors.rst'
35--- doc/for-test-authors.rst 2011-07-27 20:21:53 +0000
36+++ doc/for-test-authors.rst 2011-08-14 12:18:23 +0000
37@@ -312,6 +312,17 @@
38 self.assertThat(foo, Is(foo))
39
40
41+Is
42+~~~
43+
44+Adapts isinstance() to use as a matcher. For example::
45+
46+ def test_isinstance_example(self):
47+ class MyClass:pass
48+ self.assertThat(MyClass(), IsInstance(MyClass))
49+ self.assertThat(MyClass(), IsInstance(MyClass, str))
50+
51+
52 The raises helper
53 ~~~~~~~~~~~~~~~~~
54
55@@ -374,6 +385,16 @@
56 self.assertThat('underground', EndsWith('und'))
57
58
59+Contains
60+~~~~~~~~
61+
62+This matcher checks to see if the given thing contains the thing in the
63+matcher. For example::
64+
65+ def test_contains_example(self):
66+ self.assertThat('abc', Contains('b'))
67+
68+
69 MatchesException
70 ~~~~~~~~~~~~~~~~
71
72@@ -474,6 +495,11 @@
73 def test_annotate_example_2(self):
74 self.assertThat("orange", PoliticallyEquals("yellow"))
75
76+You can have assertThat perform the annotation for you as a convenience::
77+
78+ def test_annotate_example_3(self):
79+ self.assertThat("orange", Equals("yellow"), "Death to the aristos!")
80+
81
82 AfterPreprocessing
83 ~~~~~~~~~~~~~~~~~~
84
85=== modified file 'testtools/matchers.py'
86--- testtools/matchers.py 2011-08-08 11:14:01 +0000
87+++ testtools/matchers.py 2011-08-14 12:18:23 +0000
88@@ -15,11 +15,13 @@
89 'AfterPreprocessing',
90 'AllMatch',
91 'Annotate',
92+ 'Contains',
93 'DocTestMatches',
94 'EndsWith',
95 'Equals',
96 'GreaterThan',
97 'Is',
98+ 'IsInstance',
99 'KeysEqual',
100 'LessThan',
101 'MatchesAll',
102@@ -242,6 +244,21 @@
103 return self.matcher._describe_difference(self.with_nl)
104
105
106+class DoesNotContain(Mismatch):
107+
108+ def __init__(self, matchee, needle):
109+ """Create a DoesNotContain Mismatch.
110+
111+ :param matchee: the object that did not contain needle.
112+ :param needle: the needle that 'matchee' was expected to contain.
113+ """
114+ self.matchee = matchee
115+ self.needle = needle
116+
117+ def describe(self):
118+ return "%r not present in %r" % (self.needle, self.matchee)
119+
120+
121 class DoesNotStartWith(Mismatch):
122
123 def __init__(self, matchee, expected):
124@@ -343,6 +360,42 @@
125 mismatch_string = 'is not'
126
127
128+class IsInstance(object):
129+ """Matcher that wraps isinstance."""
130+
131+ def __init__(self, *types):
132+ self.types = tuple(types)
133+
134+ def __str__(self):
135+ return "%s(%s)" % (self.__class__.__name__,
136+ ', '.join(type.__name__ for type in self.types))
137+
138+ def match(self, other):
139+ if isinstance(other, self.types):
140+ return None
141+ return NotAnInstance(other, self.types)
142+
143+
144+class NotAnInstance(Mismatch):
145+
146+ def __init__(self, matchee, types):
147+ """Create a NotAnInstance Mismatch.
148+
149+ :param matchee: the thing which is not an instance of any of types.
150+ :param types: A tuple of the types which were expected.
151+ """
152+ self.matchee = matchee
153+ self.types = types
154+
155+ def describe(self):
156+ if len(self.types) == 1:
157+ typestr = self.types[0].__name__
158+ else:
159+ typestr = 'any of (%s)' % ', '.join(type.__name__ for type in
160+ self.types)
161+ return "'%s' is not an instance of %s" % (self.matchee, typestr)
162+
163+
164 class LessThan(_BinaryComparison):
165 """Matches if the item is less than the matchers reference object."""
166
167@@ -449,7 +502,8 @@
168 :param exception: Either an exception instance or type.
169 If an instance is given, the type and arguments of the exception
170 are checked. If a type is given only the type of the exception is
171- checked.
172+ checked. If a tuple is given, then as with isinstance, any of the
173+ types in the tuple matching is sufficient to match.
174 :param value_re: If 'exception' is a type, and the matchee exception
175 is of the right type, then match against this. If value_re is a
176 string, then assume value_re is a regular expression and match
177@@ -461,7 +515,7 @@
178 if istext(value_re):
179 value_re = AfterPreproccessing(str, MatchesRegex(value_re), False)
180 self.value_re = value_re
181- self._is_instance = type(self.expected) not in classtypes()
182+ self._is_instance = type(self.expected) not in classtypes() + (tuple,)
183
184 def match(self, other):
185 if type(other) != tuple:
186@@ -484,6 +538,29 @@
187 return "MatchesException(%s)" % repr(self.expected)
188
189
190+class Contains(Matcher):
191+ """Checks whether something is container in another thing."""
192+
193+ def __init__(self, needle):
194+ """Create a Contains Matcher.
195+
196+ :param needle: the thing that needs to be contained by matchees.
197+ """
198+ self.needle = needle
199+
200+ def __str__(self):
201+ return "Contains(%r)" % (self.needle,)
202+
203+ def match(self, matchee):
204+ try:
205+ if self.needle not in matchee:
206+ return DoesNotContain(matchee, self.needle)
207+ except TypeError:
208+ # e.g. 1 in 2 will raise TypeError
209+ return DoesNotContain(matchee, self.needle)
210+ return None
211+
212+
213 class StartsWith(Matcher):
214 """Checks whether one string starts with another."""
215
216@@ -613,16 +690,19 @@
217 # Catch all exceptions: Raises() should be able to match a
218 # KeyboardInterrupt or SystemExit.
219 except:
220+ exc_info = sys.exc_info()
221 if self.exception_matcher:
222- mismatch = self.exception_matcher.match(sys.exc_info())
223+ mismatch = self.exception_matcher.match(exc_info)
224 if not mismatch:
225+ del exc_info
226 return
227 else:
228 mismatch = None
229 # The exception did not match, or no explicit matching logic was
230 # performed. If the exception is a non-user exception (that is, not
231 # a subclass of Exception on Python 2.5+) then propogate it.
232- if isbaseexception(sys.exc_info()[1]):
233+ if isbaseexception(exc_info[1]):
234+ del exc_info
235 raise
236 return mismatch
237
238
239=== modified file 'testtools/testcase.py'
240--- testtools/testcase.py 2011-07-27 19:47:22 +0000
241+++ testtools/testcase.py 2011-08-14 12:18:23 +0000
242@@ -27,10 +27,14 @@
243 from testtools.compat import advance_iterator
244 from testtools.matchers import (
245 Annotate,
246+ Contains,
247 Equals,
248+ MatchesAll,
249 MatchesException,
250 Is,
251+ IsInstance,
252 Not,
253+ Raises,
254 )
255 from testtools.monkey import patch
256 from testtools.runtest import RunTest
257@@ -304,16 +308,14 @@
258 :param observed: The observed value.
259 :param message: An optional message to include in the error.
260 """
261- matcher = Annotate.if_message(message, Equals(expected))
262- self.assertThat(observed, matcher)
263+ matcher = Equals(expected)
264+ self.assertThat(observed, matcher, message)
265
266 failUnlessEqual = assertEquals = assertEqual
267
268 def assertIn(self, needle, haystack):
269 """Assert that needle is in haystack."""
270- # XXX: Re-implement with matchers.
271- if needle not in haystack:
272- self.fail('%r not in %r' % (needle, haystack))
273+ self.assertThat(haystack, Contains(needle))
274
275 def assertIsNone(self, observed, message=''):
276 """Assert that 'observed' is equal to None.
277@@ -321,8 +323,8 @@
278 :param observed: The observed value.
279 :param message: An optional message describing the error.
280 """
281- matcher = Annotate.if_message(message, Is(None))
282- self.assertThat(observed, matcher)
283+ matcher = Is(None)
284+ self.assertThat(observed, matcher, message)
285
286 def assertIsNotNone(self, observed, message=''):
287 """Assert that 'observed' is not equal to None.
288@@ -330,8 +332,8 @@
289 :param observed: The observed value.
290 :param message: An optional message describing the error.
291 """
292- matcher = Annotate.if_message(message, Not(Is(None)))
293- self.assertThat(observed, matcher)
294+ matcher = Not(Is(None))
295+ self.assertThat(observed, matcher, message)
296
297 def assertIs(self, expected, observed, message=''):
298 """Assert that 'expected' is 'observed'.
299@@ -340,33 +342,25 @@
300 :param observed: The observed value.
301 :param message: An optional message describing the error.
302 """
303- # XXX: Re-implement with matchers.
304- if message:
305- message = ': ' + message
306- if expected is not observed:
307- self.fail('%r is not %r%s' % (expected, observed, message))
308+ matcher = Is(expected)
309+ self.assertThat(observed, matcher, message)
310
311 def assertIsNot(self, expected, observed, message=''):
312 """Assert that 'expected' is not 'observed'."""
313- # XXX: Re-implement with matchers.
314- if message:
315- message = ': ' + message
316- if expected is observed:
317- self.fail('%r is %r%s' % (expected, observed, message))
318+ matcher = Not(Is(expected))
319+ self.assertThat(observed, matcher, message)
320
321 def assertNotIn(self, needle, haystack):
322 """Assert that needle is not in haystack."""
323- # XXX: Re-implement with matchers.
324- if needle in haystack:
325- self.fail('%r in %r' % (needle, haystack))
326+ matcher = Not(Contains(needle))
327+ self.assertThat(haystack, matcher)
328
329 def assertIsInstance(self, obj, klass, msg=None):
330- # XXX: Re-implement with matchers.
331- if msg is None:
332- msg = '%r is not an instance of %s' % (
333- obj, self._formatTypes(klass))
334- if not isinstance(obj, klass):
335- self.fail(msg)
336+ if isinstance(klass, tuple):
337+ matcher = IsInstance(*klass)
338+ else:
339+ matcher = IsInstance(klass)
340+ self.assertThat(obj, matcher, msg)
341
342 def assertRaises(self, excClass, callableObj, *args, **kwargs):
343 """Fail unless an exception of class excClass is thrown
344@@ -376,17 +370,22 @@
345 deemed to have suffered an error, exactly as for an
346 unexpected exception.
347 """
348- # XXX: Re-implement with matchers.
349- try:
350- ret = callableObj(*args, **kwargs)
351- except excClass:
352- return sys.exc_info()[1]
353- else:
354- excName = self._formatTypes(excClass)
355- self.fail("%s not raised, %r returned instead." % (excName, ret))
356+ class ReRaiseOtherTypes(object):
357+ def match(self, matchee):
358+ if not issubclass(matchee[0], excClass):
359+ raise matchee[0], matchee[1], matchee[2]
360+ class CaptureMatchee(object):
361+ def match(self, matchee):
362+ self.matchee = matchee[1]
363+ capture = CaptureMatchee()
364+ matcher = Raises(MatchesAll(ReRaiseOtherTypes(),
365+ MatchesException(excClass), capture))
366+
367+ self.assertThat(lambda:callableObj(*args, **kwargs), matcher)
368+ return capture.matchee
369 failUnlessRaises = assertRaises
370
371- def assertThat(self, matchee, matcher, verbose=False):
372+ def assertThat(self, matchee, matcher, message='', verbose=False):
373 """Assert that matchee is matched by matcher.
374
375 :param matchee: An object to match with matcher.
376@@ -395,6 +394,7 @@
377 """
378 # XXX: Should this take an optional 'message' parameter? Would kind of
379 # make sense. The hamcrest one does.
380+ matcher = Annotate.if_message(message, matcher)
381 mismatch = matcher.match(matchee)
382 if not mismatch:
383 return
384@@ -433,6 +433,7 @@
385 be removed. This separation preserves the original intent of the test
386 while it is in the expectFailure mode.
387 """
388+ # TODO: implement with matchers.
389 self._add_reason(reason)
390 try:
391 predicate(*args, **kwargs)
392
393=== modified file 'testtools/tests/test_matchers.py'
394--- testtools/tests/test_matchers.py 2011-08-08 11:14:01 +0000
395+++ testtools/tests/test_matchers.py 2011-08-14 12:18:23 +0000
396@@ -19,6 +19,7 @@
397 AllMatch,
398 Annotate,
399 AnnotatedMismatch,
400+ Contains,
401 Equals,
402 DocTestMatches,
403 DoesNotEndWith,
404@@ -26,6 +27,7 @@
405 EndsWith,
406 KeysEqual,
407 Is,
408+ IsInstance,
409 LessThan,
410 GreaterThan,
411 MatchesAny,
412@@ -179,6 +181,26 @@
413 describe_examples = [("1 is not 2", 2, Is(1))]
414
415
416+class TestIsInstanceInterface(TestCase, TestMatchersInterface):
417+
418+ class Foo:pass
419+
420+ matches_matcher = IsInstance(Foo)
421+ matches_matches = [Foo()]
422+ matches_mismatches = [object(), 1, Foo]
423+
424+ str_examples = [
425+ ("IsInstance(str)", IsInstance(str)),
426+ ("IsInstance(str, int)", IsInstance(str, int)),
427+ ]
428+
429+ describe_examples = [
430+ ("'foo' is not an instance of int", 'foo', IsInstance(int)),
431+ ("'foo' is not an instance of any of (int, type)", 'foo',
432+ IsInstance(int, type)),
433+ ]
434+
435+
436 class TestLessThanInterface(TestCase, TestMatchersInterface):
437
438 matches_matcher = LessThan(4)
439@@ -211,6 +233,20 @@
440 ]
441
442
443+class TestContainsInterface(TestCase, TestMatchersInterface):
444+
445+ matches_matcher = Contains('foo')
446+ matches_matches = ['foo', 'afoo', 'fooa']
447+ matches_mismatches = ['f', 'fo', 'oo', 'faoo', 'foao']
448+
449+ str_examples = [
450+ ("Contains(1)", Contains(1)),
451+ ("Contains('foo')", Contains('foo')),
452+ ]
453+
454+ describe_examples = [("1 not present in 2", 2, Contains(1))]
455+
456+
457 def make_error(type, *args, **kwargs):
458 try:
459 raise type(*args, **kwargs)
460
461=== modified file 'testtools/tests/test_testcase.py'
462--- testtools/tests/test_testcase.py 2011-07-26 23:48:48 +0000
463+++ testtools/tests/test_testcase.py 2011-08-14 12:18:23 +0000
464@@ -2,6 +2,7 @@
465
466 """Tests for extensions to the base test library."""
467
468+from doctest import ELLIPSIS
469 from pprint import pformat
470 import sys
471 import unittest
472@@ -20,6 +21,8 @@
473 )
474 from testtools.compat import _b
475 from testtools.matchers import (
476+ Annotate,
477+ DocTestMatches,
478 Equals,
479 MatchesException,
480 Raises,
481@@ -244,16 +247,8 @@
482 # assertRaises raises self.failureException when it's passed a
483 # callable that raises no error.
484 ret = ('orange', 42)
485- try:
486- self.assertRaises(RuntimeError, lambda: ret)
487- except self.failureException:
488- # We expected assertRaises to raise this exception.
489- e = sys.exc_info()[1]
490- self.assertEqual(
491- '%s not raised, %r returned instead.'
492- % (self._formatTypes(RuntimeError), ret), str(e))
493- else:
494- self.fail('Expected assertRaises to fail, but it did not.')
495+ self.assertFails("<function <lambda> at ...> returned ('orange', 42)",
496+ self.assertRaises, RuntimeError, lambda: ret)
497
498 def test_assertRaises_fails_when_different_error_raised(self):
499 # assertRaises re-raises an exception that it didn't expect.
500@@ -298,15 +293,14 @@
501 failure = self.assertRaises(
502 self.failureException,
503 self.assertRaises, expectedExceptions, lambda: None)
504- self.assertEqual(
505- '%s not raised, None returned instead.'
506- % self._formatTypes(expectedExceptions), str(failure))
507+ self.assertFails('<function <lambda> at ...> returned None',
508+ self.assertRaises, expectedExceptions, lambda: None)
509
510 def assertFails(self, message, function, *args, **kwargs):
511 """Assert that function raises a failure with the given message."""
512 failure = self.assertRaises(
513 self.failureException, function, *args, **kwargs)
514- self.assertEqual(message, str(failure))
515+ self.assertThat(failure, DocTestMatches(message, ELLIPSIS))
516
517 def test_assertIn_success(self):
518 # assertIn(needle, haystack) asserts that 'needle' is in 'haystack'.
519@@ -317,9 +311,9 @@
520 def test_assertIn_failure(self):
521 # assertIn(needle, haystack) fails the test when 'needle' is not in
522 # 'haystack'.
523- self.assertFails('3 not in [0, 1, 2]', self.assertIn, 3, [0, 1, 2])
524+ self.assertFails('3 not present in [0, 1, 2]', self.assertIn, 3, [0, 1, 2])
525 self.assertFails(
526- '%r not in %r' % ('qux', 'foo bar baz'),
527+ '%r not present in %r' % ('qux', 'foo bar baz'),
528 self.assertIn, 'qux', 'foo bar baz')
529
530 def test_assertNotIn_success(self):
531@@ -331,9 +325,10 @@
532 def test_assertNotIn_failure(self):
533 # assertNotIn(needle, haystack) fails the test when 'needle' is in
534 # 'haystack'.
535- self.assertFails('3 in [1, 2, 3]', self.assertNotIn, 3, [1, 2, 3])
536+ self.assertFails('[1, 2, 3] matches Contains(3)', self.assertNotIn,
537+ 3, [1, 2, 3])
538 self.assertFails(
539- '%r in %r' % ('foo', 'foo bar baz'),
540+ "'foo bar baz' matches Contains('foo')",
541 self.assertNotIn, 'foo', 'foo bar baz')
542
543 def test_assertIsInstance(self):
544@@ -367,7 +362,7 @@
545 """Simple class for testing assertIsInstance."""
546
547 self.assertFails(
548- '42 is not an instance of %s' % self._formatTypes(Foo),
549+ "'42' is not an instance of %s" % self._formatTypes(Foo),
550 self.assertIsInstance, 42, Foo)
551
552 def test_assertIsInstance_failure_multiple_classes(self):
553@@ -381,12 +376,13 @@
554 """Another simple class for testing assertIsInstance."""
555
556 self.assertFails(
557- '42 is not an instance of %s' % self._formatTypes([Foo, Bar]),
558+ "'42' is not an instance of any of (%s)" % self._formatTypes([Foo, Bar]),
559 self.assertIsInstance, 42, (Foo, Bar))
560
561 def test_assertIsInstance_overridden_message(self):
562 # assertIsInstance(obj, klass, msg) permits a custom message.
563- self.assertFails("foo", self.assertIsInstance, 42, str, "foo")
564+ self.assertFails("'42' is not an instance of str: foo",
565+ self.assertIsInstance, 42, str, "foo")
566
567 def test_assertIs(self):
568 # assertIs asserts that an object is identical to another object.
569@@ -418,16 +414,17 @@
570 def test_assertIsNot_fails(self):
571 # assertIsNot raises assertion errors if one object is identical to
572 # another.
573- self.assertFails('None is None', self.assertIsNot, None, None)
574+ self.assertFails('None matches Is(None)', self.assertIsNot, None, None)
575 some_list = [42]
576 self.assertFails(
577- '[42] is [42]', self.assertIsNot, some_list, some_list)
578+ '[42] matches Is([42])', self.assertIsNot, some_list, some_list)
579
580 def test_assertIsNot_fails_with_message(self):
581 # assertIsNot raises assertion errors if one object is identical to
582 # another, and includes a user-supplied message if it's provided.
583 self.assertFails(
584- 'None is None: foo bar', self.assertIsNot, None, None, "foo bar")
585+ 'None matches Is(None): foo bar', self.assertIsNot, None, None,
586+ "foo bar")
587
588 def test_assertThat_matches_clean(self):
589 class Matcher(object):
590@@ -468,6 +465,12 @@
591 expected = matcher.match(matchee).describe()
592 self.assertFails(expected, self.assertThat, matchee, matcher)
593
594+ def test_assertThat_message_is_annotated(self):
595+ matchee = 'foo'
596+ matcher = Equals('bar')
597+ expected = Annotate('woo', matcher).match(matchee).describe()
598+ self.assertFails(expected, self.assertThat, matchee, matcher, 'woo')
599+
600 def test_assertThat_verbose_output(self):
601 matchee = 'foo'
602 matcher = Equals('bar')

Subscribers

People subscribed via source and target branches