1 # Copyright (c) 2008 Jonathan M. Lange. See LICENSE for details.
3 """Tests for extensions to the base test library."""
8 from testtools
import (
10 clone_test_with_new_id
,
17 from testtools
.matchers
import (
20 from testtools
.tests
.helpers
import (
29 class TestEquality(TestCase
):
30 """Test `TestCase`'s equality implementation."""
32 def test_identicalIsEqual(self
):
33 # TestCase's are equal if they are identical.
34 self
.assertEqual(self
, self
)
36 def test_nonIdenticalInUnequal(self
):
37 # TestCase's are not equal if they are not identical.
38 self
.assertNotEqual(TestCase(methodName
='run'),
39 TestCase(methodName
='skip'))
42 class TestAssertions(TestCase
):
43 """Test assertions in TestCase."""
45 def raiseError(self
, exceptionFactory
, *args
, **kwargs
):
46 raise exceptionFactory(*args
, **kwargs
)
48 def test_formatTypes_single(self
):
49 # Given a single class, _formatTypes returns the name.
52 self
.assertEqual('Foo', self
._formatTypes
(Foo
))
54 def test_formatTypes_multiple(self
):
55 # Given multiple types, _formatTypes returns the names joined by
61 self
.assertEqual('Foo, Bar', self
._formatTypes
([Foo
, Bar
]))
63 def test_assertRaises(self
):
64 # assertRaises asserts that a callable raises a particular exception.
65 self
.assertRaises(RuntimeError, self
.raiseError
, RuntimeError)
67 def test_assertRaises_fails_when_no_error_raised(self
):
68 # assertRaises raises self.failureException when it's passed a
69 # callable that raises no error.
72 self
.assertRaises(RuntimeError, lambda: ret
)
73 except self
.failureException
:
74 # We expected assertRaises to raise this exception.
77 '%s not raised, %r returned instead.'
78 % (self
._formatTypes
(RuntimeError), ret
), str(e
))
80 self
.fail('Expected assertRaises to fail, but it did not.')
82 def test_assertRaises_fails_when_different_error_raised(self
):
83 # assertRaises re-raises an exception that it didn't expect.
87 RuntimeError, self
.raiseError
, ZeroDivisionError)
89 def test_assertRaises_returns_the_raised_exception(self
):
90 # assertRaises returns the exception object that was raised. This is
91 # useful for testing that exceptions have the right message.
93 # This contraption stores the raised exception, so we can compare it
94 # to the return value of assertRaises.
98 raise RuntimeError('Deliberate error')
100 raisedExceptions
.append(sys
.exc_info()[1])
103 exception
= self
.assertRaises(RuntimeError, raiseError
)
104 self
.assertEqual(1, len(raisedExceptions
))
106 exception
is raisedExceptions
[0],
107 "%r is not %r" % (exception
, raisedExceptions
[0]))
109 def test_assertRaises_with_multiple_exceptions(self
):
110 # assertRaises((ExceptionOne, ExceptionTwo), function) asserts that
111 # function raises one of ExceptionTwo or ExceptionOne.
112 expectedExceptions
= (RuntimeError, ZeroDivisionError)
114 expectedExceptions
, self
.raiseError
, expectedExceptions
[0])
116 expectedExceptions
, self
.raiseError
, expectedExceptions
[1])
118 def test_assertRaises_with_multiple_exceptions_failure_mode(self
):
119 # If assertRaises is called expecting one of a group of exceptions and
120 # a callable that doesn't raise an exception, then fail with an
121 # appropriate error message.
122 expectedExceptions
= (RuntimeError, ZeroDivisionError)
123 failure
= self
.assertRaises(
124 self
.failureException
,
125 self
.assertRaises
, expectedExceptions
, lambda: None)
127 '%s not raised, None returned instead.'
128 % self
._formatTypes
(expectedExceptions
), str(failure
))
130 def assertFails(self
, message
, function
, *args
, **kwargs
):
131 """Assert that function raises a failure with the given message."""
132 failure
= self
.assertRaises(
133 self
.failureException
, function
, *args
, **kwargs
)
134 self
.assertEqual(message
, str(failure
))
136 def test_assertIn_success(self
):
137 # assertIn(needle, haystack) asserts that 'needle' is in 'haystack'.
138 self
.assertIn(3, range(10))
139 self
.assertIn('foo', 'foo bar baz')
140 self
.assertIn('foo', 'foo bar baz'.split())
142 def test_assertIn_failure(self
):
143 # assertIn(needle, haystack) fails the test when 'needle' is not in
145 self
.assertFails('3 not in [0, 1, 2]', self
.assertIn
, 3, [0, 1, 2])
147 '%r not in %r' % ('qux', 'foo bar baz'),
148 self
.assertIn
, 'qux', 'foo bar baz')
150 def test_assertNotIn_success(self
):
151 # assertNotIn(needle, haystack) asserts that 'needle' is not in
153 self
.assertNotIn(3, [0, 1, 2])
154 self
.assertNotIn('qux', 'foo bar baz')
156 def test_assertNotIn_failure(self
):
157 # assertNotIn(needle, haystack) fails the test when 'needle' is in
159 self
.assertFails('3 in [1, 2, 3]', self
.assertNotIn
, 3, [1, 2, 3])
161 '%r in %r' % ('foo', 'foo bar baz'),
162 self
.assertNotIn
, 'foo', 'foo bar baz')
164 def test_assertIsInstance(self
):
165 # assertIsInstance asserts that an object is an instance of a class.
168 """Simple class for testing assertIsInstance."""
171 self
.assertIsInstance(foo
, Foo
)
173 def test_assertIsInstance_multiple_classes(self
):
174 # assertIsInstance asserts that an object is an instance of one of a
178 """Simple class for testing assertIsInstance."""
181 """Another simple class for testing assertIsInstance."""
184 self
.assertIsInstance(foo
, (Foo
, Bar
))
185 self
.assertIsInstance(Bar(), (Foo
, Bar
))
187 def test_assertIsInstance_failure(self
):
188 # assertIsInstance(obj, klass) fails the test when obj is not an
192 """Simple class for testing assertIsInstance."""
195 '42 is not an instance of %s' % self
._formatTypes
(Foo
),
196 self
.assertIsInstance
, 42, Foo
)
198 def test_assertIsInstance_failure_multiple_classes(self
):
199 # assertIsInstance(obj, (klass1, klass2)) fails the test when obj is
200 # not an instance of klass1 or klass2.
203 """Simple class for testing assertIsInstance."""
206 """Another simple class for testing assertIsInstance."""
209 '42 is not an instance of %s' % self
._formatTypes
([Foo
, Bar
]),
210 self
.assertIsInstance
, 42, (Foo
, Bar
))
212 def test_assertIs(self
):
213 # assertIs asserts that an object is identical to another object.
214 self
.assertIs(None, None)
216 self
.assertIs(some_list
, some_list
)
217 some_object
= object()
218 self
.assertIs(some_object
, some_object
)
220 def test_assertIs_fails(self
):
221 # assertIs raises assertion errors if one object is not identical to
223 self
.assertFails('None is not 42', self
.assertIs
, None, 42)
224 self
.assertFails('[42] is not [42]', self
.assertIs
, [42], [42])
226 def test_assertIs_fails_with_message(self
):
227 # assertIs raises assertion errors if one object is not identical to
228 # another, and includes a user-supplied message, if it's provided.
230 'None is not 42: foo bar', self
.assertIs
, None, 42, 'foo bar')
232 def test_assertIsNot(self
):
233 # assertIsNot asserts that an object is not identical to another
235 self
.assertIsNot(None, 42)
236 self
.assertIsNot([42], [42])
237 self
.assertIsNot(object(), object())
239 def test_assertIsNot_fails(self
):
240 # assertIsNot raises assertion errors if one object is identical to
242 self
.assertFails('None is None', self
.assertIsNot
, None, None)
245 '[42] is [42]', self
.assertIsNot
, some_list
, some_list
)
247 def test_assertIsNot_fails_with_message(self
):
248 # assertIsNot raises assertion errors if one object is identical to
249 # another, and includes a user-supplied message if it's provided.
251 'None is None: foo bar', self
.assertIsNot
, None, None, "foo bar")
253 def test_assertThat_matches_clean(self
):
255 def match(self
, foo
):
257 self
.assertThat("foo", Matcher())
259 def test_assertThat_mismatch_raises_description(self
):
262 def __init__(self
, thing
):
265 calls
.append(('describe_diff', self
.thing
))
266 return "object is not a thing"
268 def match(self
, thing
):
269 calls
.append(('match', thing
))
270 return Mismatch(thing
)
272 calls
.append(('__str__',))
273 return "a description"
274 class Test(TestCase
):
276 self
.assertThat("foo", Matcher())
277 result
= Test("test").run()
280 ('describe_diff', "foo"),
283 self
.assertFalse(result
.wasSuccessful())
286 class TestAddCleanup(TestCase
):
287 """Tests for TestCase.addCleanup."""
289 class LoggingTest(TestCase
):
290 """A test that logs calls to setUp, runTest and tearDown."""
294 self
._calls
= ['setUp']
296 def brokenSetUp(self
):
297 # A tearDown that deliberately fails.
298 self
._calls
= ['brokenSetUp']
299 raise RuntimeError('Deliberate Failure')
302 self
._calls
.append('runTest')
305 self
._calls
.append('tearDown')
306 TestCase
.tearDown(self
)
310 self
._result
_calls
= []
311 self
.test
= TestAddCleanup
.LoggingTest('runTest')
312 self
.logging_result
= LoggingResult(self
._result
_calls
)
314 def assertErrorLogEqual(self
, messages
):
315 self
.assertEqual(messages
, [call
[0] for call
in self
._result
_calls
])
317 def assertTestLogEqual(self
, messages
):
318 """Assert that the call log equals 'messages'."""
319 case
= self
._result
_calls
[0][1]
320 self
.assertEqual(messages
, case
._calls
)
322 def logAppender(self
, message
):
323 """A cleanup that appends 'message' to the tests log.
325 Cleanups are callables that are added to a test by addCleanup. To
326 verify that our cleanups run in the right order, we add strings to a
327 list that acts as a log. This method returns a cleanup that will add
328 the given message to that log when run.
330 self
.test
._calls
.append(message
)
332 def test_fixture(self
):
333 # A normal run of self.test logs 'setUp', 'runTest' and 'tearDown'.
334 # This test doesn't test addCleanup itself, it just sanity checks the
336 self
.test
.run(self
.logging_result
)
337 self
.assertTestLogEqual(['setUp', 'runTest', 'tearDown'])
339 def test_cleanup_run_before_tearDown(self
):
340 # Cleanup functions added with 'addCleanup' are called before tearDown
342 self
.test
.addCleanup(self
.logAppender
, 'cleanup')
343 self
.test
.run(self
.logging_result
)
344 self
.assertTestLogEqual(['setUp', 'runTest', 'tearDown', 'cleanup'])
346 def test_add_cleanup_called_if_setUp_fails(self
):
347 # Cleanup functions added with 'addCleanup' are called even if setUp
348 # fails. Note that tearDown has a different behavior: it is only
349 # called when setUp succeeds.
350 self
.test
.setUp
= self
.test
.brokenSetUp
351 self
.test
.addCleanup(self
.logAppender
, 'cleanup')
352 self
.test
.run(self
.logging_result
)
353 self
.assertTestLogEqual(['brokenSetUp', 'cleanup'])
355 def test_addCleanup_called_in_reverse_order(self
):
356 # Cleanup functions added with 'addCleanup' are called in reverse
359 # One of the main uses of addCleanup is to dynamically create
360 # resources that need some sort of explicit tearDown. Often one
361 # resource will be created in terms of another, e.g.,
362 # self.first = self.makeFirst()
363 # self.second = self.makeSecond(self.first)
365 # When this happens, we generally want to clean up the second resource
366 # before the first one, since the second depends on the first.
367 self
.test
.addCleanup(self
.logAppender
, 'first')
368 self
.test
.addCleanup(self
.logAppender
, 'second')
369 self
.test
.run(self
.logging_result
)
370 self
.assertTestLogEqual(
371 ['setUp', 'runTest', 'tearDown', 'second', 'first'])
373 def test_tearDown_runs_after_cleanup_failure(self
):
374 # tearDown runs even if a cleanup function fails.
375 self
.test
.addCleanup(lambda: 1/0)
376 self
.test
.run(self
.logging_result
)
377 self
.assertTestLogEqual(['setUp', 'runTest', 'tearDown'])
379 def test_cleanups_continue_running_after_error(self
):
380 # All cleanups are always run, even if one or two of them fail.
381 self
.test
.addCleanup(self
.logAppender
, 'first')
382 self
.test
.addCleanup(lambda: 1/0)
383 self
.test
.addCleanup(self
.logAppender
, 'second')
384 self
.test
.run(self
.logging_result
)
385 self
.assertTestLogEqual(
386 ['setUp', 'runTest', 'tearDown', 'second', 'first'])
388 def test_error_in_cleanups_are_captured(self
):
389 # If a cleanup raises an error, we want to record it and fail the the
390 # test, even though we go on to run other cleanups.
391 self
.test
.addCleanup(lambda: 1/0)
392 self
.test
.run(self
.logging_result
)
393 self
.assertErrorLogEqual(['startTest', 'addError', 'stopTest'])
395 def test_keyboard_interrupt_not_caught(self
):
396 # If a cleanup raises KeyboardInterrupt, it gets reraised.
397 def raiseKeyboardInterrupt():
398 raise KeyboardInterrupt()
399 self
.test
.addCleanup(raiseKeyboardInterrupt
)
401 KeyboardInterrupt, self
.test
.run
, self
.logging_result
)
403 def test_multipleErrorsReported(self
):
404 # Errors from all failing cleanups are reported.
405 self
.test
.addCleanup(lambda: 1/0)
406 self
.test
.addCleanup(lambda: 1/0)
407 self
.test
.run(self
.logging_result
)
408 self
.assertErrorLogEqual(
409 ['startTest', 'addError', 'addError', 'stopTest'])
412 class TestWithDetails(TestCase
):
414 def assertDetailsProvided(self
, case
, expected_outcome
, expected_keys
):
415 """Assert that when case is run, details are provided to the result.
417 :param case: A TestCase to run.
418 :param expected_outcome: The call that should be made.
419 :param expected_keys: The keys to look for.
421 result
= ExtendedTestResult()
423 case
= result
._events
[0][1]
426 (expected_outcome
, case
),
429 self
.assertEqual(3, len(result
._events
))
430 self
.assertEqual(expected
[0], result
._events
[0])
431 self
.assertEqual(expected
[1], result
._events
[1][0:2])
432 # Checking the TB is right is rather tricky. doctest line matching
433 # would help, but 'meh'.
434 self
.assertEqual(sorted(expected_keys
),
435 sorted(result
._events
[1][2].keys()))
436 self
.assertEqual(expected
[-1], result
._events
[-1])
438 def get_content(self
):
439 return content
.Content(
440 content
.ContentType("text", "foo"), lambda: ['foo'])
443 class TestExpectedFailure(TestWithDetails
):
444 """Tests for expected failures and unexpected successess."""
446 def make_unexpected_case(self
):
447 class Case(TestCase
):
449 raise testcase
._UnexpectedSuccess
453 def test_raising__UnexpectedSuccess_py27(self
):
454 case
= self
.make_unexpected_case()
455 result
= Python27TestResult()
457 case
= result
._events
[0][1]
460 ('addUnexpectedSuccess', case
),
464 def test_raising__UnexpectedSuccess_extended(self
):
465 case
= self
.make_unexpected_case()
466 result
= ExtendedTestResult()
468 case
= result
._events
[0][1]
471 ('addUnexpectedSuccess', case
, {}),
475 def make_xfail_case_xfails(self
):
476 content
= self
.get_content()
477 class Case(TestCase
):
479 self
.addDetail("foo", content
)
480 self
.expectFailure("we are sad", self
.assertEqual
,
485 def make_xfail_case_succeeds(self
):
486 content
= self
.get_content()
487 class Case(TestCase
):
489 self
.addDetail("foo", content
)
490 self
.expectFailure("we are sad", self
.assertEqual
,
495 def test_expectFailure_KnownFailure_extended(self
):
496 case
= self
.make_xfail_case_xfails()
497 self
.assertDetailsProvided(case
, "addExpectedFailure",
498 ["foo", "traceback", "reason"])
500 def test_expectFailure_KnownFailure_unexpected_success(self
):
501 case
= self
.make_xfail_case_succeeds()
502 self
.assertDetailsProvided(case
, "addUnexpectedSuccess",
506 class TestUniqueFactories(TestCase
):
507 """Tests for getUniqueString and getUniqueInteger."""
509 def test_getUniqueInteger(self
):
510 # getUniqueInteger returns an integer that increments each time you
512 one
= self
.getUniqueInteger()
513 self
.assertEqual(1, one
)
514 two
= self
.getUniqueInteger()
515 self
.assertEqual(2, two
)
517 def test_getUniqueString(self
):
518 # getUniqueString returns the current test id followed by a unique
520 name_one
= self
.getUniqueString()
521 self
.assertEqual('%s-%d' % (self
.id(), 1), name_one
)
522 name_two
= self
.getUniqueString()
523 self
.assertEqual('%s-%d' % (self
.id(), 2), name_two
)
525 def test_getUniqueString_prefix(self
):
526 # If getUniqueString is given an argument, it uses that argument as
527 # the prefix of the unique string, rather than the test id.
528 name_one
= self
.getUniqueString('foo')
529 self
.assertThat(name_one
, Equals('foo-1'))
530 name_two
= self
.getUniqueString('bar')
531 self
.assertThat(name_two
, Equals('bar-2'))
534 class TestCloneTestWithNewId(TestCase
):
535 """Tests for clone_test_with_new_id."""
537 def test_clone_test_with_new_id(self
):
538 class FooTestCase(TestCase
):
541 test
= FooTestCase('test_foo')
543 newName
= self
.getUniqueString()
544 newTest
= clone_test_with_new_id(test
, newName
)
545 self
.assertEqual(newName
, newTest
.id())
546 self
.assertEqual(oldName
, test
.id(),
547 "the original test instance should be unchanged.")
550 class TestDetailsProvided(TestWithDetails
):
552 def test_addDetail(self
):
553 mycontent
= self
.get_content()
554 self
.addDetail("foo", mycontent
)
555 details
= self
.getDetails()
556 self
.assertEqual({"foo": mycontent
}, details
)
558 def test_addError(self
):
559 class Case(TestCase
):
561 this
.addDetail("foo", self
.get_content())
563 self
.assertDetailsProvided(Case("test"), "addError",
564 ["foo", "traceback"])
566 def test_addFailure(self
):
567 class Case(TestCase
):
569 this
.addDetail("foo", self
.get_content())
571 self
.assertDetailsProvided(Case("test"), "addFailure",
572 ["foo", "traceback"])
574 def test_addSkip(self
):
575 class Case(TestCase
):
577 this
.addDetail("foo", self
.get_content())
579 self
.assertDetailsProvided(Case("test"), "addSkip",
582 def test_addSucccess(self
):
583 class Case(TestCase
):
585 this
.addDetail("foo", self
.get_content())
586 self
.assertDetailsProvided(Case("test"), "addSuccess",
589 def test_addUnexpectedSuccess(self
):
590 class Case(TestCase
):
592 this
.addDetail("foo", self
.get_content())
593 raise testcase
._UnexpectedSuccess
()
594 self
.assertDetailsProvided(Case("test"), "addUnexpectedSuccess",
598 class TestSetupTearDown(TestCase
):
600 def test_setUpNotCalled(self
):
601 class DoesnotcallsetUp(TestCase
):
604 def test_method(self
):
606 result
= unittest
.TestResult()
607 DoesnotcallsetUp('test_method').run(result
)
608 self
.assertEqual(1, len(result
.errors
))
610 def test_tearDownNotCalled(self
):
611 class DoesnotcalltearDown(TestCase
):
612 def test_method(self
):
616 result
= unittest
.TestResult()
617 DoesnotcalltearDown('test_method').run(result
)
618 self
.assertEqual(1, len(result
.errors
))
621 class TestSkipping(TestCase
):
622 """Tests for skipping of tests functionality."""
624 def test_skip_causes_skipException(self
):
625 self
.assertRaises(self
.skipException
, self
.skip
, "Skip this test")
627 def test_skip_without_reason_works(self
):
628 class Test(TestCase
):
630 raise self
.skipException()
632 result
= ExtendedTestResult()
634 self
.assertEqual('addSkip', result
._events
[1][0])
635 self
.assertEqual('no reason given.',
636 ''.join(result
._events
[1][2]['reason'].iter_text()))
638 def test_skipException_in_setup_calls_result_addSkip(self
):
639 class TestThatRaisesInSetUp(TestCase
):
642 self
.skip("skipping this test")
643 def test_that_passes(self
):
646 result
= LoggingResult(calls
)
647 test
= TestThatRaisesInSetUp("test_that_passes")
649 case
= result
._events
[0][1]
650 self
.assertEqual([('startTest', case
),
651 ('addSkip', case
, "Text attachment: reason\n------------\n"
652 "skipping this test\n------------\n"), ('stopTest', case
)],
655 def test_skipException_in_test_method_calls_result_addSkip(self
):
656 class SkippingTest(TestCase
):
657 def test_that_raises_skipException(self
):
658 self
.skip("skipping this test")
659 result
= Python27TestResult()
660 test
= SkippingTest("test_that_raises_skipException")
662 case
= result
._events
[0][1]
663 self
.assertEqual([('startTest', case
),
664 ('addSkip', case
, "Text attachment: reason\n------------\n"
665 "skipping this test\n------------\n"), ('stopTest', case
)],
668 def test_skip__in_setup_with_old_result_object_calls_addSuccess(self
):
669 class SkippingTest(TestCase
):
672 raise self
.skipException("skipping this test")
673 def test_that_raises_skipException(self
):
675 result
= Python26TestResult()
676 test
= SkippingTest("test_that_raises_skipException")
678 self
.assertEqual('addSuccess', result
._events
[1][0])
680 def test_skip_with_old_result_object_calls_addError(self
):
681 class SkippingTest(TestCase
):
682 def test_that_raises_skipException(self
):
683 raise self
.skipException("skipping this test")
684 result
= Python26TestResult()
685 test
= SkippingTest("test_that_raises_skipException")
687 self
.assertEqual('addSuccess', result
._events
[1][0])
689 def test_skip_decorator(self
):
690 class SkippingTest(TestCase
):
691 @skip("skipping this test")
692 def test_that_is_decorated_with_skip(self
):
694 result
= Python26TestResult()
695 test
= SkippingTest("test_that_is_decorated_with_skip")
697 self
.assertEqual('addSuccess', result
._events
[1][0])
699 def test_skipIf_decorator(self
):
700 class SkippingTest(TestCase
):
701 @skipIf(True, "skipping this test")
702 def test_that_is_decorated_with_skipIf(self
):
704 result
= Python26TestResult()
705 test
= SkippingTest("test_that_is_decorated_with_skipIf")
707 self
.assertEqual('addSuccess', result
._events
[1][0])
709 def test_skipUnless_decorator(self
):
710 class SkippingTest(TestCase
):
711 @skipUnless(False, "skipping this test")
712 def test_that_is_decorated_with_skipUnless(self
):
714 result
= Python26TestResult()
715 test
= SkippingTest("test_that_is_decorated_with_skipUnless")
717 self
.assertEqual('addSuccess', result
._events
[1][0])
720 class TestOnException(TestCase
):
722 def test_default_works(self
):
724 class Case(TestCase
):
726 self
.onException(an_exc_info
)
728 case
= Case("method")
730 self
.assertThat(events
, Equals([True]))
732 def test_added_handler_works(self
):
734 class Case(TestCase
):
736 self
.addOnException(events
.append
)
737 self
.onException(an_exc_info
)
738 case
= Case("method")
740 self
.assertThat(events
, Equals([an_exc_info
]))
742 def test_handler_that_raises_is_not_caught(self
):
744 class Case(TestCase
):
746 self
.addOnException(events
.index
)
747 self
.assertRaises(ValueError, self
.onException
, an_exc_info
)
748 case
= Case("method")
750 self
.assertThat(events
, Equals([]))
754 from unittest
import TestLoader
755 return TestLoader().loadTestsFromName(__name__
)