772
762
self.check_timing(ShortDelayTestCase('test_short_delay'),
765
def _patch_get_bzr_source_tree(self):
766
# Reading from the actual source tree breaks isolation, but we don't
767
# want to assume that thats *all* that would happen.
768
self.overrideAttr(bzrlib.version, '_get_bzr_source_tree', lambda: None)
770
def test_assigned_benchmark_file_stores_date(self):
771
self._patch_get_bzr_source_tree()
773
result = bzrlib.tests.TextTestResult(self._log_file,
778
output_string = output.getvalue()
779
# if you are wondering about the regexp please read the comment in
780
# test_bench_history (bzrlib.tests.test_selftest.TestRunner)
781
# XXX: what comment? -- Andrew Bennetts
782
self.assertContainsRe(output_string, "--date [0-9.]+")
784
def test_benchhistory_records_test_times(self):
785
self._patch_get_bzr_source_tree()
786
result_stream = StringIO()
787
result = bzrlib.tests.TextTestResult(
791
bench_history=result_stream
794
# we want profile a call and check that its test duration is recorded
795
# make a new test instance that when run will generate a benchmark
796
example_test_case = TestTestResult("_time_hello_world_encoding")
797
# execute the test, which should succeed and record times
798
example_test_case.run(result)
799
lines = result_stream.getvalue().splitlines()
800
self.assertEqual(2, len(lines))
801
self.assertContainsRe(lines[1],
802
" *[0-9]+ms bzrlib.tests.test_selftest.TestTestResult"
803
"._time_hello_world_encoding")
775
805
def _time_hello_world_encoding(self):
776
806
"""Profile two sleep calls
1217
def test_verbose_test_count(self):
1218
"""A verbose test run reports the right test count at the start"""
1219
suite = TestUtil.TestSuite([
1220
unittest.FunctionTestCase(lambda:None),
1221
unittest.FunctionTestCase(lambda:None)])
1222
self.assertEqual(suite.countTestCases(), 2)
1224
runner = tests.TextTestRunner(stream=stream, verbosity=2)
1225
# Need to use the CountingDecorator as that's what sets num_tests
1226
result = self.run_test_runner(runner, tests.CountingDecorator(suite))
1227
self.assertStartsWith(stream.getvalue(), "running 2 tests")
1214
def _patch_get_bzr_source_tree(self):
1215
# Reading from the actual source tree breaks isolation, but we don't
1216
# want to assume that thats *all* that would happen.
1217
self._get_source_tree_calls = []
1219
self._get_source_tree_calls.append("called")
1221
self.overrideAttr(bzrlib.version, '_get_bzr_source_tree', new_get)
1223
def test_bench_history(self):
1224
# tests that the running the benchmark passes bench_history into
1225
# the test result object. We can tell that happens if
1226
# _get_bzr_source_tree is called.
1227
self._patch_get_bzr_source_tree()
1228
test = TestRunner('dummy_test')
1230
runner = tests.TextTestRunner(stream=self._log_file,
1231
bench_history=output)
1232
result = self.run_test_runner(runner, test)
1233
output_string = output.getvalue()
1234
self.assertContainsRe(output_string, "--date [0-9.]+")
1235
self.assertLength(1, self._get_source_tree_calls)
1229
1237
def test_startTestRun(self):
1230
1238
"""run should call result.startTestRun()"""
1232
class LoggingDecorator(ExtendedToOriginalDecorator):
1240
class LoggingDecorator(tests.ForwardingResult):
1233
1241
def startTestRun(self):
1234
ExtendedToOriginalDecorator.startTestRun(self)
1242
tests.ForwardingResult.startTestRun(self)
1235
1243
calls.append('startTestRun')
1236
1244
test = unittest.FunctionTestCase(lambda:None)
1237
1245
stream = StringIO()
1685
1676
self.assertEqual('original', obj.test_attr)
1688
class _MissingFeature(tests.Feature):
1691
missing_feature = _MissingFeature()
1694
def _get_test(name):
1695
"""Get an instance of a specific example test.
1697
We protect this in a function so that they don't auto-run in the test
1701
class ExampleTests(tests.TestCase):
1703
def test_fail(self):
1704
mutter('this was a failing test')
1705
self.fail('this test will fail')
1707
def test_error(self):
1708
mutter('this test errored')
1709
raise RuntimeError('gotcha')
1711
def test_missing_feature(self):
1712
mutter('missing the feature')
1713
self.requireFeature(missing_feature)
1715
def test_skip(self):
1716
mutter('this test will be skipped')
1717
raise tests.TestSkipped('reason')
1719
def test_success(self):
1720
mutter('this test succeeds')
1722
def test_xfail(self):
1723
mutter('test with expected failure')
1724
self.knownFailure('this_fails')
1726
def test_unexpected_success(self):
1727
mutter('test with unexpected success')
1728
self.expectFailure('should_fail', lambda: None)
1730
return ExampleTests(name)
1733
class TestTestCaseLogDetails(tests.TestCase):
1735
def _run_test(self, test_name):
1736
test = _get_test(test_name)
1737
result = testtools.TestResult()
1741
def test_fail_has_log(self):
1742
result = self._run_test('test_fail')
1743
self.assertEqual(1, len(result.failures))
1744
result_content = result.failures[0][1]
1745
self.assertContainsRe(result_content, 'Text attachment: log')
1746
self.assertContainsRe(result_content, 'this was a failing test')
1748
def test_error_has_log(self):
1749
result = self._run_test('test_error')
1750
self.assertEqual(1, len(result.errors))
1751
result_content = result.errors[0][1]
1752
self.assertContainsRe(result_content, 'Text attachment: log')
1753
self.assertContainsRe(result_content, 'this test errored')
1755
def test_skip_has_no_log(self):
1756
result = self._run_test('test_skip')
1757
self.assertEqual(['reason'], result.skip_reasons.keys())
1758
skips = result.skip_reasons['reason']
1759
self.assertEqual(1, len(skips))
1761
self.assertFalse('log' in test.getDetails())
1763
def test_missing_feature_has_no_log(self):
1764
# testtools doesn't know about addNotSupported, so it just gets
1765
# considered as a skip
1766
result = self._run_test('test_missing_feature')
1767
self.assertEqual([missing_feature], result.skip_reasons.keys())
1768
skips = result.skip_reasons[missing_feature]
1769
self.assertEqual(1, len(skips))
1771
self.assertFalse('log' in test.getDetails())
1773
def test_xfail_has_no_log(self):
1774
result = self._run_test('test_xfail')
1775
self.assertEqual(1, len(result.expectedFailures))
1776
result_content = result.expectedFailures[0][1]
1777
self.assertNotContainsRe(result_content, 'Text attachment: log')
1778
self.assertNotContainsRe(result_content, 'test with expected failure')
1780
def test_unexpected_success_has_log(self):
1781
result = self._run_test('test_unexpected_success')
1782
self.assertEqual(1, len(result.unexpectedSuccesses))
1783
# Inconsistency, unexpectedSuccesses is a list of tests,
1784
# expectedFailures is a list of reasons?
1785
test = result.unexpectedSuccesses[0]
1786
details = test.getDetails()
1787
self.assertTrue('log' in details)
1790
class TestTestCloning(tests.TestCase):
1791
"""Tests that test cloning of TestCases (as used by multiply_tests)."""
1793
def test_cloned_testcase_does_not_share_details(self):
1794
"""A TestCase cloned with clone_test does not share mutable attributes
1795
such as details or cleanups.
1797
class Test(tests.TestCase):
1799
self.addDetail('foo', Content('text/plain', lambda: 'foo'))
1800
orig_test = Test('test_foo')
1801
cloned_test = tests.clone_test(orig_test, orig_test.id() + '(cloned)')
1802
orig_test.run(unittest.TestResult())
1803
self.assertEqual('foo', orig_test.getDetails()['foo'].iter_bytes())
1804
self.assertEqual(None, cloned_test.getDetails().get('foo'))
1806
def test_double_apply_scenario_preserves_first_scenario(self):
1807
"""Applying two levels of scenarios to a test preserves the attributes
1808
added by both scenarios.
1810
class Test(tests.TestCase):
1813
test = Test('test_foo')
1814
scenarios_x = [('x=1', {'x': 1}), ('x=2', {'x': 2})]
1815
scenarios_y = [('y=1', {'y': 1}), ('y=2', {'y': 2})]
1816
suite = tests.multiply_tests(test, scenarios_x, unittest.TestSuite())
1817
suite = tests.multiply_tests(suite, scenarios_y, unittest.TestSuite())
1818
all_tests = list(tests.iter_suite_tests(suite))
1819
self.assertLength(4, all_tests)
1820
all_xys = sorted((t.x, t.y) for t in all_tests)
1821
self.assertEqual([(1, 1), (1, 2), (2, 1), (2, 2)], all_xys)
1824
1679
# NB: Don't delete this; it's not actually from 0.11!
1825
1680
@deprecated_function(deprecated_in((0, 11, 0)))
1826
1681
def sample_deprecated_function():
2134
1992
load_list='missing file name', list_only=True)
2137
class TestSubunitLogDetails(tests.TestCase, SelfTestHelper):
2139
_test_needs_features = [features.subunit]
2141
def run_subunit_stream(self, test_name):
2142
from subunit import ProtocolTestCase
2144
return TestUtil.TestSuite([_get_test(test_name)])
2145
stream = self.run_selftest(runner_class=tests.SubUnitBzrRunner,
2146
test_suite_factory=factory)
2147
test = ProtocolTestCase(stream)
2148
result = testtools.TestResult()
2150
content = stream.getvalue()
2151
return content, result
2153
def test_fail_has_log(self):
2154
content, result = self.run_subunit_stream('test_fail')
2155
self.assertEqual(1, len(result.failures))
2156
self.assertContainsRe(content, '(?m)^log$')
2157
self.assertContainsRe(content, 'this test will fail')
2159
def test_error_has_log(self):
2160
content, result = self.run_subunit_stream('test_error')
2161
self.assertContainsRe(content, '(?m)^log$')
2162
self.assertContainsRe(content, 'this test errored')
2164
def test_skip_has_no_log(self):
2165
content, result = self.run_subunit_stream('test_skip')
2166
self.assertNotContainsRe(content, '(?m)^log$')
2167
self.assertNotContainsRe(content, 'this test will be skipped')
2168
self.assertEqual(['reason'], result.skip_reasons.keys())
2169
skips = result.skip_reasons['reason']
2170
self.assertEqual(1, len(skips))
2172
# RemotedTestCase doesn't preserve the "details"
2173
## self.assertFalse('log' in test.getDetails())
2175
def test_missing_feature_has_no_log(self):
2176
content, result = self.run_subunit_stream('test_missing_feature')
2177
self.assertNotContainsRe(content, '(?m)^log$')
2178
self.assertNotContainsRe(content, 'missing the feature')
2179
self.assertEqual(['_MissingFeature\n'], result.skip_reasons.keys())
2180
skips = result.skip_reasons['_MissingFeature\n']
2181
self.assertEqual(1, len(skips))
2183
# RemotedTestCase doesn't preserve the "details"
2184
## self.assertFalse('log' in test.getDetails())
2186
def test_xfail_has_no_log(self):
2187
content, result = self.run_subunit_stream('test_xfail')
2188
self.assertNotContainsRe(content, '(?m)^log$')
2189
self.assertNotContainsRe(content, 'test with expected failure')
2190
self.assertEqual(1, len(result.expectedFailures))
2191
result_content = result.expectedFailures[0][1]
2192
self.assertNotContainsRe(result_content, 'Text attachment: log')
2193
self.assertNotContainsRe(result_content, 'test with expected failure')
2195
def test_unexpected_success_has_log(self):
2196
content, result = self.run_subunit_stream('test_unexpected_success')
2197
self.assertContainsRe(content, '(?m)^log$')
2198
self.assertContainsRe(content, 'test with unexpected success')
2199
# GZ 2011-05-18: Old versions of subunit treat unexpected success as a
2200
# success, if a min version check is added remove this
2201
from subunit import TestProtocolClient as _Client
2202
if _Client.addUnexpectedSuccess.im_func is _Client.addSuccess.im_func:
2203
self.expectFailure('subunit treats "unexpectedSuccess"'
2204
' as a plain success',
2205
self.assertEqual, 1, len(result.unexpectedSuccesses))
2206
self.assertEqual(1, len(result.unexpectedSuccesses))
2207
test = result.unexpectedSuccesses[0]
2208
# RemotedTestCase doesn't preserve the "details"
2209
## self.assertTrue('log' in test.getDetails())
2211
def test_success_has_no_log(self):
2212
content, result = self.run_subunit_stream('test_success')
2213
self.assertEqual(1, result.testsRun)
2214
self.assertNotContainsRe(content, '(?m)^log$')
2215
self.assertNotContainsRe(content, 'this test succeeds')
2218
1995
class TestRunBzr(tests.TestCase):
2534
2304
def test_allow_plugins(self):
2535
2305
self.assertRaises(_DontSpawnProcess, self.start_bzr_subprocess, [],
2537
2307
command = self._popen_args[0]
2538
2308
self.assertEqual([], command[2:])
2540
2310
def test_set_env(self):
2541
self.assertFalse('EXISTANT_ENV_VAR' in os.environ)
2311
self.failIf('EXISTANT_ENV_VAR' in os.environ)
2542
2312
# set in the child
2543
2313
def check_environment():
2544
2314
self.assertEqual('set variable', os.environ['EXISTANT_ENV_VAR'])
2545
2315
self.check_popen_state = check_environment
2546
2316
self.assertRaises(_DontSpawnProcess, self.start_bzr_subprocess, [],
2547
env_changes={'EXISTANT_ENV_VAR':'set variable'})
2317
env_changes={'EXISTANT_ENV_VAR':'set variable'})
2548
2318
# not set in theparent
2549
2319
self.assertFalse('EXISTANT_ENV_VAR' in os.environ)
2551
2321
def test_run_bzr_subprocess_env_del(self):
2552
2322
"""run_bzr_subprocess can remove environment variables too."""
2553
self.assertFalse('EXISTANT_ENV_VAR' in os.environ)
2323
self.failIf('EXISTANT_ENV_VAR' in os.environ)
2554
2324
def check_environment():
2555
2325
self.assertFalse('EXISTANT_ENV_VAR' in os.environ)
2556
2326
os.environ['EXISTANT_ENV_VAR'] = 'set variable'
2557
2327
self.check_popen_state = check_environment
2558
2328
self.assertRaises(_DontSpawnProcess, self.start_bzr_subprocess, [],
2559
env_changes={'EXISTANT_ENV_VAR':None})
2329
env_changes={'EXISTANT_ENV_VAR':None})
2560
2330
# Still set in parent
2561
2331
self.assertEqual('set variable', os.environ['EXISTANT_ENV_VAR'])
2562
2332
del os.environ['EXISTANT_ENV_VAR']
2564
2334
def test_env_del_missing(self):
2565
self.assertFalse('NON_EXISTANT_ENV_VAR' in os.environ)
2335
self.failIf('NON_EXISTANT_ENV_VAR' in os.environ)
2566
2336
def check_environment():
2567
2337
self.assertFalse('NON_EXISTANT_ENV_VAR' in os.environ)
2568
2338
self.check_popen_state = check_environment
2569
2339
self.assertRaises(_DontSpawnProcess, self.start_bzr_subprocess, [],
2570
env_changes={'NON_EXISTANT_ENV_VAR':None})
2340
env_changes={'NON_EXISTANT_ENV_VAR':None})
2572
2342
def test_working_dir(self):
2573
2343
"""Test that we can specify the working dir for the child"""
3297
3074
self.assertContainsString(result.stream.getvalue(), "leaking threads")
3300
class TestPostMortemDebugging(tests.TestCase):
3301
"""Check post mortem debugging works when tests fail or error"""
3303
class TracebackRecordingResult(tests.ExtendedTestResult):
3305
tests.ExtendedTestResult.__init__(self, StringIO(), 0, 1)
3306
self.postcode = None
3307
def _post_mortem(self, tb=None):
3308
"""Record the code object at the end of the current traceback"""
3309
tb = tb or sys.exc_info()[2]
3312
while next is not None:
3315
self.postcode = tb.tb_frame.f_code
3316
def report_error(self, test, err):
3318
def report_failure(self, test, err):
3321
def test_location_unittest_error(self):
3322
"""Needs right post mortem traceback with erroring unittest case"""
3323
class Test(unittest.TestCase):
3326
result = self.TracebackRecordingResult()
3328
self.assertEqual(result.postcode, Test.runTest.func_code)
3330
def test_location_unittest_failure(self):
3331
"""Needs right post mortem traceback with failing unittest case"""
3332
class Test(unittest.TestCase):
3334
raise self.failureException
3335
result = self.TracebackRecordingResult()
3337
self.assertEqual(result.postcode, Test.runTest.func_code)
3339
def test_location_bt_error(self):
3340
"""Needs right post mortem traceback with erroring bzrlib.tests case"""
3341
class Test(tests.TestCase):
3342
def test_error(self):
3344
result = self.TracebackRecordingResult()
3345
Test("test_error").run(result)
3346
self.assertEqual(result.postcode, Test.test_error.func_code)
3348
def test_location_bt_failure(self):
3349
"""Needs right post mortem traceback with failing bzrlib.tests case"""
3350
class Test(tests.TestCase):
3351
def test_failure(self):
3352
raise self.failureException
3353
result = self.TracebackRecordingResult()
3354
Test("test_failure").run(result)
3355
self.assertEqual(result.postcode, Test.test_failure.func_code)
3357
def test_env_var_triggers_post_mortem(self):
3358
"""Check pdb.post_mortem is called iff BZR_TEST_PDB is set"""
3360
result = tests.ExtendedTestResult(StringIO(), 0, 1)
3361
post_mortem_calls = []
3362
self.overrideAttr(pdb, "post_mortem", post_mortem_calls.append)
3363
self.overrideEnv('BZR_TEST_PDB', None)
3364
result._post_mortem(1)
3365
self.overrideEnv('BZR_TEST_PDB', 'on')
3366
result._post_mortem(2)
3367
self.assertEqual([2], post_mortem_calls)
3370
3077
class TestRunSuite(tests.TestCase):
3372
3079
def test_runner_class(self):
3383
3090
self.verbosity)
3384
3091
tests.run_suite(suite, runner_class=MyRunner, stream=StringIO())
3385
3092
self.assertLength(1, calls)
3388
class TestEnvironHandling(tests.TestCase):
3390
def test_overrideEnv_None_called_twice_doesnt_leak(self):
3391
self.assertFalse('MYVAR' in os.environ)
3392
self.overrideEnv('MYVAR', '42')
3393
# We use an embedded test to make sure we fix the _captureVar bug
3394
class Test(tests.TestCase):
3396
# The first call save the 42 value
3397
self.overrideEnv('MYVAR', None)
3398
self.assertEquals(None, os.environ.get('MYVAR'))
3399
# Make sure we can call it twice
3400
self.overrideEnv('MYVAR', None)
3401
self.assertEquals(None, os.environ.get('MYVAR'))
3403
result = tests.TextTestResult(output, 0, 1)
3404
Test('test_me').run(result)
3405
if not result.wasStrictlySuccessful():
3406
self.fail(output.getvalue())
3407
# We get our value back
3408
self.assertEquals('42', os.environ.get('MYVAR'))
3411
class TestIsolatedEnv(tests.TestCase):
3412
"""Test isolating tests from os.environ.
3414
Since we use tests that are already isolated from os.environ a bit of care
3415
should be taken when designing the tests to avoid bootstrap side-effects.
3416
The tests start an already clean os.environ which allow doing valid
3417
assertions about which variables are present or not and design tests around
3421
class ScratchMonkey(tests.TestCase):
3426
def test_basics(self):
3427
# Make sure we know the definition of BZR_HOME: not part of os.environ
3428
# for tests.TestCase.
3429
self.assertTrue('BZR_HOME' in tests.isolated_environ)
3430
self.assertEquals(None, tests.isolated_environ['BZR_HOME'])
3431
# Being part of isolated_environ, BZR_HOME should not appear here
3432
self.assertFalse('BZR_HOME' in os.environ)
3433
# Make sure we know the definition of LINES: part of os.environ for
3435
self.assertTrue('LINES' in tests.isolated_environ)
3436
self.assertEquals('25', tests.isolated_environ['LINES'])
3437
self.assertEquals('25', os.environ['LINES'])
3439
def test_injecting_unknown_variable(self):
3440
# BZR_HOME is known to be absent from os.environ
3441
test = self.ScratchMonkey('test_me')
3442
tests.override_os_environ(test, {'BZR_HOME': 'foo'})
3443
self.assertEquals('foo', os.environ['BZR_HOME'])
3444
tests.restore_os_environ(test)
3445
self.assertFalse('BZR_HOME' in os.environ)
3447
def test_injecting_known_variable(self):
3448
test = self.ScratchMonkey('test_me')
3449
# LINES is known to be present in os.environ
3450
tests.override_os_environ(test, {'LINES': '42'})
3451
self.assertEquals('42', os.environ['LINES'])
3452
tests.restore_os_environ(test)
3453
self.assertEquals('25', os.environ['LINES'])
3455
def test_deleting_variable(self):
3456
test = self.ScratchMonkey('test_me')
3457
# LINES is known to be present in os.environ
3458
tests.override_os_environ(test, {'LINES': None})
3459
self.assertTrue('LINES' not in os.environ)
3460
tests.restore_os_environ(test)
3461
self.assertEquals('25', os.environ['LINES'])
3464
class TestDocTestSuiteIsolation(tests.TestCase):
3465
"""Test that `tests.DocTestSuite` isolates doc tests from os.environ.
3467
Since tests.TestCase alreay provides an isolation from os.environ, we use
3468
the clean environment as a base for testing. To precisely capture the
3469
isolation provided by tests.DocTestSuite, we use doctest.DocTestSuite to
3472
We want to make sure `tests.DocTestSuite` respect `tests.isolated_environ`,
3473
not `os.environ` so each test overrides it to suit its needs.
3477
def get_doctest_suite_for_string(self, klass, string):
3478
class Finder(doctest.DocTestFinder):
3480
def find(*args, **kwargs):
3481
test = doctest.DocTestParser().get_doctest(
3482
string, {}, 'foo', 'foo.py', 0)
3485
suite = klass(test_finder=Finder())
3488
def run_doctest_suite_for_string(self, klass, string):
3489
suite = self.get_doctest_suite_for_string(klass, string)
3491
result = tests.TextTestResult(output, 0, 1)
3493
return result, output
3495
def assertDocTestStringSucceds(self, klass, string):
3496
result, output = self.run_doctest_suite_for_string(klass, string)
3497
if not result.wasStrictlySuccessful():
3498
self.fail(output.getvalue())
3500
def assertDocTestStringFails(self, klass, string):
3501
result, output = self.run_doctest_suite_for_string(klass, string)
3502
if result.wasStrictlySuccessful():
3503
self.fail(output.getvalue())
3505
def test_injected_variable(self):
3506
self.overrideAttr(tests, 'isolated_environ', {'LINES': '42'})
3509
>>> os.environ['LINES']
3512
# doctest.DocTestSuite fails as it sees '25'
3513
self.assertDocTestStringFails(doctest.DocTestSuite, test)
3514
# tests.DocTestSuite sees '42'
3515
self.assertDocTestStringSucceds(tests.IsolatedDocTestSuite, test)
3517
def test_deleted_variable(self):
3518
self.overrideAttr(tests, 'isolated_environ', {'LINES': None})
3521
>>> os.environ.get('LINES')
3523
# doctest.DocTestSuite fails as it sees '25'
3524
self.assertDocTestStringFails(doctest.DocTestSuite, test)
3525
# tests.DocTestSuite sees None
3526
self.assertDocTestStringSucceds(tests.IsolatedDocTestSuite, test)
3529
class TestSelftestExcludePatterns(tests.TestCase):
3532
super(TestSelftestExcludePatterns, self).setUp()
3533
self.overrideAttr(tests, 'test_suite', self.suite_factory)
3535
def suite_factory(self, keep_only=None, starting_with=None):
3536
"""A test suite factory with only a few tests."""
3537
class Test(tests.TestCase):
3539
# We don't need the full class path
3540
return self._testMethodName
3547
return TestUtil.TestSuite([Test("a"), Test("b"), Test("c")])
3549
def assertTestList(self, expected, *selftest_args):
3550
# We rely on setUp installing the right test suite factory so we can
3551
# test at the command level without loading the whole test suite
3552
out, err = self.run_bzr(('selftest', '--list') + selftest_args)
3553
actual = out.splitlines()
3554
self.assertEquals(expected, actual)
3556
def test_full_list(self):
3557
self.assertTestList(['a', 'b', 'c'])
3559
def test_single_exclude(self):
3560
self.assertTestList(['b', 'c'], '-x', 'a')
3562
def test_mutiple_excludes(self):
3563
self.assertTestList(['c'], '-x', 'a', '-x', 'b')
3566
class TestCounterHooks(tests.TestCase, SelfTestHelper):
3568
_test_needs_features = [features.subunit]
3571
super(TestCounterHooks, self).setUp()
3572
class Test(tests.TestCase):
3575
super(Test, self).setUp()
3576
self.hooks = hooks.Hooks()
3577
self.hooks.add_hook('myhook', 'Foo bar blah', (2,4))
3578
self.install_counter_hook(self.hooks, 'myhook')
3583
def run_hook_once(self):
3584
for hook in self.hooks['myhook']:
3587
self.test_class = Test
3589
def assertHookCalls(self, expected_calls, test_name):
3590
test = self.test_class(test_name)
3591
result = unittest.TestResult()
3593
self.assertTrue(hasattr(test, '_counters'))
3594
self.assertTrue(test._counters.has_key('myhook'))
3595
self.assertEquals(expected_calls, test._counters['myhook'])
3597
def test_no_hook(self):
3598
self.assertHookCalls(0, 'no_hook')
3600
def test_run_hook_once(self):
3601
tt = features.testtools
3602
if tt.module.__version__ < (0, 9, 8):
3603
raise tests.TestSkipped('testtools-0.9.8 required for addDetail')
3604
self.assertHookCalls(1, 'run_hook_once')