1
0
mirror of https://github.com/samba-team/samba.git synced 2025-07-27 07:42:04 +03:00
Files
samba-mirror/lib/subunit/python/testtools/tests/test_testtools.py
2010-01-16 19:53:49 +13:00

744 lines
27 KiB
Python

# Copyright (c) 2008 Jonathan M. Lange. See LICENSE for details.
"""Tests for extensions to the base test library."""
import sys
import unittest
from testtools import (
TestCase,
clone_test_with_new_id,
content,
skip,
skipIf,
skipUnless,
testcase,
)
from testtools.matchers import (
Equals,
)
from testtools.tests.helpers import (
an_exc_info,
LoggingResult,
Python26TestResult,
Python27TestResult,
ExtendedTestResult,
)
class TestEquality(TestCase):
"""Test `TestCase`'s equality implementation."""
def test_identicalIsEqual(self):
# TestCase's are equal if they are identical.
self.assertEqual(self, self)
def test_nonIdenticalInUnequal(self):
# TestCase's are not equal if they are not identical.
self.assertNotEqual(TestCase(methodName='run'),
TestCase(methodName='skip'))
class TestAssertions(TestCase):
"""Test assertions in TestCase."""
def raiseError(self, exceptionFactory, *args, **kwargs):
raise exceptionFactory(*args, **kwargs)
def test_formatTypes_single(self):
# Given a single class, _formatTypes returns the name.
class Foo:
pass
self.assertEqual('Foo', self._formatTypes(Foo))
def test_formatTypes_multiple(self):
# Given multiple types, _formatTypes returns the names joined by
# commas.
class Foo:
pass
class Bar:
pass
self.assertEqual('Foo, Bar', self._formatTypes([Foo, Bar]))
def test_assertRaises(self):
# assertRaises asserts that a callable raises a particular exception.
self.assertRaises(RuntimeError, self.raiseError, RuntimeError)
def test_assertRaises_fails_when_no_error_raised(self):
# assertRaises raises self.failureException when it's passed a
# callable that raises no error.
ret = ('orange', 42)
try:
self.assertRaises(RuntimeError, lambda: ret)
except self.failureException:
# We expected assertRaises to raise this exception.
e = sys.exc_info()[1]
self.assertEqual(
'%s not raised, %r returned instead.'
% (self._formatTypes(RuntimeError), ret), str(e))
else:
self.fail('Expected assertRaises to fail, but it did not.')
def test_assertRaises_fails_when_different_error_raised(self):
# assertRaises re-raises an exception that it didn't expect.
self.assertRaises(
ZeroDivisionError,
self.assertRaises,
RuntimeError, self.raiseError, ZeroDivisionError)
def test_assertRaises_returns_the_raised_exception(self):
# assertRaises returns the exception object that was raised. This is
# useful for testing that exceptions have the right message.
# This contraption stores the raised exception, so we can compare it
# to the return value of assertRaises.
raisedExceptions = []
def raiseError():
try:
raise RuntimeError('Deliberate error')
except RuntimeError:
raisedExceptions.append(sys.exc_info()[1])
raise
exception = self.assertRaises(RuntimeError, raiseError)
self.assertEqual(1, len(raisedExceptions))
self.assertTrue(
exception is raisedExceptions[0],
"%r is not %r" % (exception, raisedExceptions[0]))
def test_assertRaises_with_multiple_exceptions(self):
# assertRaises((ExceptionOne, ExceptionTwo), function) asserts that
# function raises one of ExceptionTwo or ExceptionOne.
expectedExceptions = (RuntimeError, ZeroDivisionError)
self.assertRaises(
expectedExceptions, self.raiseError, expectedExceptions[0])
self.assertRaises(
expectedExceptions, self.raiseError, expectedExceptions[1])
def test_assertRaises_with_multiple_exceptions_failure_mode(self):
# If assertRaises is called expecting one of a group of exceptions and
# a callable that doesn't raise an exception, then fail with an
# appropriate error message.
expectedExceptions = (RuntimeError, ZeroDivisionError)
failure = self.assertRaises(
self.failureException,
self.assertRaises, expectedExceptions, lambda: None)
self.assertEqual(
'%s not raised, None returned instead.'
% self._formatTypes(expectedExceptions), str(failure))
def assertFails(self, message, function, *args, **kwargs):
"""Assert that function raises a failure with the given message."""
failure = self.assertRaises(
self.failureException, function, *args, **kwargs)
self.assertEqual(message, str(failure))
def test_assertIn_success(self):
# assertIn(needle, haystack) asserts that 'needle' is in 'haystack'.
self.assertIn(3, range(10))
self.assertIn('foo', 'foo bar baz')
self.assertIn('foo', 'foo bar baz'.split())
def test_assertIn_failure(self):
# assertIn(needle, haystack) fails the test when 'needle' is not in
# 'haystack'.
self.assertFails('3 not in [0, 1, 2]', self.assertIn, 3, [0, 1, 2])
self.assertFails(
'%r not in %r' % ('qux', 'foo bar baz'),
self.assertIn, 'qux', 'foo bar baz')
def test_assertNotIn_success(self):
# assertNotIn(needle, haystack) asserts that 'needle' is not in
# 'haystack'.
self.assertNotIn(3, [0, 1, 2])
self.assertNotIn('qux', 'foo bar baz')
def test_assertNotIn_failure(self):
# assertNotIn(needle, haystack) fails the test when 'needle' is in
# 'haystack'.
self.assertFails('3 in [1, 2, 3]', self.assertNotIn, 3, [1, 2, 3])
self.assertFails(
'%r in %r' % ('foo', 'foo bar baz'),
self.assertNotIn, 'foo', 'foo bar baz')
def test_assertIsInstance(self):
# assertIsInstance asserts that an object is an instance of a class.
class Foo:
"""Simple class for testing assertIsInstance."""
foo = Foo()
self.assertIsInstance(foo, Foo)
def test_assertIsInstance_multiple_classes(self):
# assertIsInstance asserts that an object is an instance of one of a
# group of classes.
class Foo:
"""Simple class for testing assertIsInstance."""
class Bar:
"""Another simple class for testing assertIsInstance."""
foo = Foo()
self.assertIsInstance(foo, (Foo, Bar))
self.assertIsInstance(Bar(), (Foo, Bar))
def test_assertIsInstance_failure(self):
# assertIsInstance(obj, klass) fails the test when obj is not an
# instance of klass.
class Foo:
"""Simple class for testing assertIsInstance."""
self.assertFails(
'42 is not an instance of %s' % self._formatTypes(Foo),
self.assertIsInstance, 42, Foo)
def test_assertIsInstance_failure_multiple_classes(self):
# assertIsInstance(obj, (klass1, klass2)) fails the test when obj is
# not an instance of klass1 or klass2.
class Foo:
"""Simple class for testing assertIsInstance."""
class Bar:
"""Another simple class for testing assertIsInstance."""
self.assertFails(
'42 is not an instance of %s' % self._formatTypes([Foo, Bar]),
self.assertIsInstance, 42, (Foo, Bar))
def test_assertIs(self):
# assertIs asserts that an object is identical to another object.
self.assertIs(None, None)
some_list = [42]
self.assertIs(some_list, some_list)
some_object = object()
self.assertIs(some_object, some_object)
def test_assertIs_fails(self):
# assertIs raises assertion errors if one object is not identical to
# another.
self.assertFails('None is not 42', self.assertIs, None, 42)
self.assertFails('[42] is not [42]', self.assertIs, [42], [42])
def test_assertIsNot(self):
# assertIsNot asserts that an object is not identical to another
# object.
self.assertIsNot(None, 42)
self.assertIsNot([42], [42])
self.assertIsNot(object(), object())
def test_assertIsNot_fails(self):
# assertIsNot raises assertion errors if one object is identical to
# another.
self.assertFails('None is None', self.assertIsNot, None, None)
some_list = [42]
self.assertFails(
'[42] is [42]', self.assertIsNot, some_list, some_list)
def test_assertThat_matches_clean(self):
class Matcher:
def match(self, foo):
return None
self.assertThat("foo", Matcher())
def test_assertThat_mismatch_raises_description(self):
calls = []
class Mismatch:
def __init__(self, thing):
self.thing = thing
def describe(self):
calls.append(('describe_diff', self.thing))
return "object is not a thing"
class Matcher:
def match(self, thing):
calls.append(('match', thing))
return Mismatch(thing)
def __str__(self):
calls.append(('__str__',))
return "a description"
class Test(TestCase):
def test(self):
self.assertThat("foo", Matcher())
result = Test("test").run()
self.assertEqual([
('match', "foo"),
('describe_diff', "foo"),
('__str__',),
], calls)
self.assertFalse(result.wasSuccessful())
class TestAddCleanup(TestCase):
"""Tests for TestCase.addCleanup."""
class LoggingTest(TestCase):
"""A test that logs calls to setUp, runTest and tearDown."""
def setUp(self):
TestCase.setUp(self)
self._calls = ['setUp']
def brokenSetUp(self):
# A tearDown that deliberately fails.
self._calls = ['brokenSetUp']
raise RuntimeError('Deliberate Failure')
def runTest(self):
self._calls.append('runTest')
def tearDown(self):
self._calls.append('tearDown')
TestCase.tearDown(self)
def setUp(self):
TestCase.setUp(self)
self._result_calls = []
self.test = TestAddCleanup.LoggingTest('runTest')
self.logging_result = LoggingResult(self._result_calls)
def assertErrorLogEqual(self, messages):
self.assertEqual(messages, [call[0] for call in self._result_calls])
def assertTestLogEqual(self, messages):
"""Assert that the call log equals `messages`."""
case = self._result_calls[0][1]
self.assertEqual(messages, case._calls)
def logAppender(self, message):
"""A cleanup that appends `message` to the tests log.
Cleanups are callables that are added to a test by addCleanup. To
verify that our cleanups run in the right order, we add strings to a
list that acts as a log. This method returns a cleanup that will add
the given message to that log when run.
"""
self.test._calls.append(message)
def test_fixture(self):
# A normal run of self.test logs 'setUp', 'runTest' and 'tearDown'.
# This test doesn't test addCleanup itself, it just sanity checks the
# fixture.
self.test.run(self.logging_result)
self.assertTestLogEqual(['setUp', 'runTest', 'tearDown'])
def test_cleanup_run_before_tearDown(self):
# Cleanup functions added with 'addCleanup' are called before tearDown
# runs.
self.test.addCleanup(self.logAppender, 'cleanup')
self.test.run(self.logging_result)
self.assertTestLogEqual(['setUp', 'runTest', 'tearDown', 'cleanup'])
def test_add_cleanup_called_if_setUp_fails(self):
# Cleanup functions added with 'addCleanup' are called even if setUp
# fails. Note that tearDown has a different behavior: it is only
# called when setUp succeeds.
self.test.setUp = self.test.brokenSetUp
self.test.addCleanup(self.logAppender, 'cleanup')
self.test.run(self.logging_result)
self.assertTestLogEqual(['brokenSetUp', 'cleanup'])
def test_addCleanup_called_in_reverse_order(self):
# Cleanup functions added with 'addCleanup' are called in reverse
# order.
#
# One of the main uses of addCleanup is to dynamically create
# resources that need some sort of explicit tearDown. Often one
# resource will be created in terms of another, e.g.,
# self.first = self.makeFirst()
# self.second = self.makeSecond(self.first)
#
# When this happens, we generally want to clean up the second resource
# before the first one, since the second depends on the first.
self.test.addCleanup(self.logAppender, 'first')
self.test.addCleanup(self.logAppender, 'second')
self.test.run(self.logging_result)
self.assertTestLogEqual(
['setUp', 'runTest', 'tearDown', 'second', 'first'])
def test_tearDown_runs_after_cleanup_failure(self):
# tearDown runs even if a cleanup function fails.
self.test.addCleanup(lambda: 1/0)
self.test.run(self.logging_result)
self.assertTestLogEqual(['setUp', 'runTest', 'tearDown'])
def test_cleanups_continue_running_after_error(self):
# All cleanups are always run, even if one or two of them fail.
self.test.addCleanup(self.logAppender, 'first')
self.test.addCleanup(lambda: 1/0)
self.test.addCleanup(self.logAppender, 'second')
self.test.run(self.logging_result)
self.assertTestLogEqual(
['setUp', 'runTest', 'tearDown', 'second', 'first'])
def test_error_in_cleanups_are_captured(self):
# If a cleanup raises an error, we want to record it and fail the the
# test, even though we go on to run other cleanups.
self.test.addCleanup(lambda: 1/0)
self.test.run(self.logging_result)
self.assertErrorLogEqual(['startTest', 'addError', 'stopTest'])
def test_keyboard_interrupt_not_caught(self):
# If a cleanup raises KeyboardInterrupt, it gets reraised.
def raiseKeyboardInterrupt():
raise KeyboardInterrupt()
self.test.addCleanup(raiseKeyboardInterrupt)
self.assertRaises(
KeyboardInterrupt, self.test.run, self.logging_result)
def test_multipleErrorsReported(self):
# Errors from all failing cleanups are reported.
self.test.addCleanup(lambda: 1/0)
self.test.addCleanup(lambda: 1/0)
self.test.run(self.logging_result)
self.assertErrorLogEqual(
['startTest', 'addError', 'addError', 'stopTest'])
class TestWithDetails(TestCase):
def assertDetailsProvided(self, case, expected_outcome, expected_keys):
"""Assert that when case is run, details are provided to the result.
:param case: A TestCase to run.
:param expected_outcome: The call that should be made.
:param expected_keys: The keys to look for.
"""
result = ExtendedTestResult()
case.run(result)
case = result._events[0][1]
expected = [
('startTest', case),
(expected_outcome, case),
('stopTest', case),
]
self.assertEqual(3, len(result._events))
self.assertEqual(expected[0], result._events[0])
self.assertEqual(expected[1], result._events[1][0:2])
# Checking the TB is right is rather tricky. doctest line matching
# would help, but 'meh'.
self.assertEqual(sorted(expected_keys),
sorted(result._events[1][2].keys()))
self.assertEqual(expected[-1], result._events[-1])
def get_content(self):
return content.Content(
content.ContentType("text", "foo"), lambda: ['foo'])
class TestExpectedFailure(TestWithDetails):
"""Tests for expected failures and unexpected successess."""
def make_unexpected_case(self):
class Case(TestCase):
def test(self):
raise testcase._UnexpectedSuccess
case = Case('test')
return case
def test_raising__UnexpectedSuccess_py27(self):
case = self.make_unexpected_case()
result = Python27TestResult()
case.run(result)
case = result._events[0][1]
self.assertEqual([
('startTest', case),
('addUnexpectedSuccess', case),
('stopTest', case),
], result._events)
def test_raising__UnexpectedSuccess_extended(self):
case = self.make_unexpected_case()
result = ExtendedTestResult()
case.run(result)
case = result._events[0][1]
self.assertEqual([
('startTest', case),
('addUnexpectedSuccess', case, {}),
('stopTest', case),
], result._events)
def make_xfail_case_xfails(self):
content = self.get_content()
class Case(TestCase):
def test(self):
self.addDetail("foo", content)
self.expectFailure("we are sad", self.assertEqual,
1, 0)
case = Case('test')
return case
def make_xfail_case_succeeds(self):
content = self.get_content()
class Case(TestCase):
def test(self):
self.addDetail("foo", content)
self.expectFailure("we are sad", self.assertEqual,
1, 1)
case = Case('test')
return case
def test_expectFailure_KnownFailure_extended(self):
case = self.make_xfail_case_xfails()
self.assertDetailsProvided(case, "addExpectedFailure",
["foo", "traceback", "reason"])
def test_expectFailure_KnownFailure_unexpected_success(self):
case = self.make_xfail_case_succeeds()
self.assertDetailsProvided(case, "addUnexpectedSuccess",
["foo", "reason"])
class TestUniqueFactories(TestCase):
"""Tests for getUniqueString and getUniqueInteger."""
def test_getUniqueInteger(self):
# getUniqueInteger returns an integer that increments each time you
# call it.
one = self.getUniqueInteger()
self.assertEqual(1, one)
two = self.getUniqueInteger()
self.assertEqual(2, two)
def test_getUniqueString(self):
# getUniqueString returns the current test id followed by a unique
# integer.
name_one = self.getUniqueString()
self.assertEqual('%s-%d' % (self.id(), 1), name_one)
name_two = self.getUniqueString()
self.assertEqual('%s-%d' % (self.id(), 2), name_two)
def test_getUniqueString_prefix(self):
# If getUniqueString is given an argument, it uses that argument as
# the prefix of the unique string, rather than the test id.
name_one = self.getUniqueString('foo')
self.assertThat(name_one, Equals('foo-1'))
name_two = self.getUniqueString('bar')
self.assertThat(name_two, Equals('bar-2'))
class TestCloneTestWithNewId(TestCase):
"""Tests for clone_test_with_new_id."""
def test_clone_test_with_new_id(self):
class FooTestCase(TestCase):
def test_foo(self):
pass
test = FooTestCase('test_foo')
oldName = test.id()
newName = self.getUniqueString()
newTest = clone_test_with_new_id(test, newName)
self.assertEqual(newName, newTest.id())
self.assertEqual(oldName, test.id(),
"the original test instance should be unchanged.")
class TestDetailsProvided(TestWithDetails):
def test_addDetail(self):
mycontent = self.get_content()
self.addDetail("foo", mycontent)
details = self.getDetails()
self.assertEqual({"foo": mycontent}, details)
def test_addError(self):
class Case(TestCase):
def test(this):
this.addDetail("foo", self.get_content())
1/0
self.assertDetailsProvided(Case("test"), "addError",
["foo", "traceback"])
def test_addFailure(self):
class Case(TestCase):
def test(this):
this.addDetail("foo", self.get_content())
self.fail('yo')
self.assertDetailsProvided(Case("test"), "addFailure",
["foo", "traceback"])
def test_addSkip(self):
class Case(TestCase):
def test(this):
this.addDetail("foo", self.get_content())
self.skip('yo')
self.assertDetailsProvided(Case("test"), "addSkip",
["foo", "reason"])
def test_addSucccess(self):
class Case(TestCase):
def test(this):
this.addDetail("foo", self.get_content())
self.assertDetailsProvided(Case("test"), "addSuccess",
["foo"])
def test_addUnexpectedSuccess(self):
class Case(TestCase):
def test(this):
this.addDetail("foo", self.get_content())
raise testcase._UnexpectedSuccess()
self.assertDetailsProvided(Case("test"), "addUnexpectedSuccess",
["foo"])
class TestSetupTearDown(TestCase):
def test_setUpNotCalled(self):
class DoesnotcallsetUp(TestCase):
def setUp(self):
pass
def test_method(self):
pass
result = unittest.TestResult()
DoesnotcallsetUp('test_method').run(result)
self.assertEqual(1, len(result.errors))
def test_tearDownNotCalled(self):
class DoesnotcalltearDown(TestCase):
def test_method(self):
pass
def tearDown(self):
pass
result = unittest.TestResult()
DoesnotcalltearDown('test_method').run(result)
self.assertEqual(1, len(result.errors))
class TestSkipping(TestCase):
"""Tests for skipping of tests functionality."""
def test_skip_causes_skipException(self):
self.assertRaises(self.skipException, self.skip, "Skip this test")
def test_skip_without_reason_works(self):
class Test(TestCase):
def test(self):
raise self.skipException()
case = Test("test")
result = ExtendedTestResult()
case.run(result)
self.assertEqual('addSkip', result._events[1][0])
self.assertEqual('no reason given.',
''.join(result._events[1][2]['reason'].iter_text()))
def test_skipException_in_setup_calls_result_addSkip(self):
class TestThatRaisesInSetUp(TestCase):
def setUp(self):
TestCase.setUp(self)
self.skip("skipping this test")
def test_that_passes(self):
pass
calls = []
result = LoggingResult(calls)
test = TestThatRaisesInSetUp("test_that_passes")
test.run(result)
case = result._events[0][1]
self.assertEqual([('startTest', case),
('addSkip', case, "Text attachment: reason\n------------\n"
"skipping this test\n------------\n"), ('stopTest', case)],
calls)
def test_skipException_in_test_method_calls_result_addSkip(self):
class SkippingTest(TestCase):
def test_that_raises_skipException(self):
self.skip("skipping this test")
result = Python27TestResult()
test = SkippingTest("test_that_raises_skipException")
test.run(result)
case = result._events[0][1]
self.assertEqual([('startTest', case),
('addSkip', case, "Text attachment: reason\n------------\n"
"skipping this test\n------------\n"), ('stopTest', case)],
result._events)
def test_skip__in_setup_with_old_result_object_calls_addSuccess(self):
class SkippingTest(TestCase):
def setUp(self):
TestCase.setUp(self)
raise self.skipException("skipping this test")
def test_that_raises_skipException(self):
pass
result = Python26TestResult()
test = SkippingTest("test_that_raises_skipException")
test.run(result)
self.assertEqual('addSuccess', result._events[1][0])
def test_skip_with_old_result_object_calls_addError(self):
class SkippingTest(TestCase):
def test_that_raises_skipException(self):
raise self.skipException("skipping this test")
result = Python26TestResult()
test = SkippingTest("test_that_raises_skipException")
test.run(result)
self.assertEqual('addSuccess', result._events[1][0])
def test_skip_decorator(self):
class SkippingTest(TestCase):
@skip("skipping this test")
def test_that_is_decorated_with_skip(self):
self.fail()
result = Python26TestResult()
test = SkippingTest("test_that_is_decorated_with_skip")
test.run(result)
self.assertEqual('addSuccess', result._events[1][0])
def test_skipIf_decorator(self):
class SkippingTest(TestCase):
@skipIf(True, "skipping this test")
def test_that_is_decorated_with_skipIf(self):
self.fail()
result = Python26TestResult()
test = SkippingTest("test_that_is_decorated_with_skipIf")
test.run(result)
self.assertEqual('addSuccess', result._events[1][0])
def test_skipUnless_decorator(self):
class SkippingTest(TestCase):
@skipUnless(False, "skipping this test")
def test_that_is_decorated_with_skipUnless(self):
self.fail()
result = Python26TestResult()
test = SkippingTest("test_that_is_decorated_with_skipUnless")
test.run(result)
self.assertEqual('addSuccess', result._events[1][0])
class TestOnException(TestCase):
def test_default_works(self):
events = []
class Case(TestCase):
def method(self):
self.onException(an_exc_info)
events.append(True)
case = Case("method")
case.run()
self.assertThat(events, Equals([True]))
def test_added_handler_works(self):
events = []
class Case(TestCase):
def method(self):
self.addOnException(events.append)
self.onException(an_exc_info)
case = Case("method")
case.run()
self.assertThat(events, Equals([an_exc_info]))
def test_handler_that_raises_is_not_caught(self):
events = []
class Case(TestCase):
def method(self):
self.addOnException(events.index)
self.assertRaises(ValueError, self.onException, an_exc_info)
case = Case("method")
case.run()
self.assertThat(events, Equals([]))
def test_suite():
from unittest import TestLoader
return TestLoader().loadTestsFromName(__name__)