1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078 |
- # Copyright (c) Twisted Matrix Laboratories.
- # See LICENSE for details.
- #
- # Maintainer: Jonathan Lange
- # Author: Robert Collins
- from __future__ import absolute_import, division
- import os
- import pdb
- import sys
- from zope.interface import implementer
- from zope.interface.verify import verifyObject
- from twisted.trial.itrial import IReporter, ITestCase
- from twisted.trial import unittest, runner, reporter, util
- from twisted.trial._asyncrunner import _ForceGarbageCollectionDecorator
- from twisted.python import failure, log, reflect
- from twisted.python.filepath import FilePath
- from twisted.python.reflect import namedAny
- from twisted.python.compat import NativeStringIO
- from twisted.scripts import trial
- from twisted.plugins import twisted_trial
- from twisted import plugin
- from twisted.internet import defer
- pyunit = __import__('unittest')
- class CapturingDebugger(object):
- def __init__(self):
- self._calls = []
- def runcall(self, *args, **kwargs):
- self._calls.append('runcall')
- args[0](*args[1:], **kwargs)
- @implementer(IReporter)
- class CapturingReporter(object):
- """
- Reporter that keeps a log of all actions performed on it.
- """
- stream = None
- tbformat = None
- args = None
- separator = None
- testsRun = None
- def __init__(self, stream=None, tbformat=None, rterrors=None,
- publisher=None):
- """
- Create a capturing reporter.
- """
- self._calls = []
- self.shouldStop = False
- self._stream = stream
- self._tbformat = tbformat
- self._rterrors = rterrors
- self._publisher = publisher
- def startTest(self, method):
- """
- Report the beginning of a run of a single test method
- @param method: an object that is adaptable to ITestMethod
- """
- self._calls.append('startTest')
- def stopTest(self, method):
- """
- Report the status of a single test method
- @param method: an object that is adaptable to ITestMethod
- """
- self._calls.append('stopTest')
- def cleanupErrors(self, errs):
- """called when the reactor has been left in a 'dirty' state
- @param errs: a list of L{twisted.python.failure.Failure}s
- """
- self._calls.append('cleanupError')
- def addSuccess(self, test):
- self._calls.append('addSuccess')
- def done(self):
- """
- Do nothing. These tests don't care about done.
- """
- class TrialRunnerTestsMixin(object):
- """
- Mixin defining tests for L{runner.TrialRunner}.
- """
- def tearDown(self):
- self.runner._tearDownLogFile()
- def test_empty(self):
- """
- Empty test method, used by the other tests.
- """
- def _getObservers(self):
- return log.theLogPublisher.observers
- def test_addObservers(self):
- """
- Any log system observers L{TrialRunner.run} adds are removed by the
- time it returns.
- """
- originalCount = len(self._getObservers())
- self.runner.run(self.test)
- newCount = len(self._getObservers())
- self.assertEqual(newCount, originalCount)
- def test_logFileAlwaysActive(self):
- """
- Test that a new file is opened on each run.
- """
- oldSetUpLogFile = self.runner._setUpLogFile
- l = []
- def setUpLogFile():
- oldSetUpLogFile()
- l.append(self.runner._logFileObserver)
- self.runner._setUpLogFile = setUpLogFile
- self.runner.run(self.test)
- self.runner.run(self.test)
- self.assertEqual(len(l), 2)
- self.assertFalse(l[0] is l[1], "Should have created a new file observer")
- def test_logFileGetsClosed(self):
- """
- Test that file created is closed during the run.
- """
- oldSetUpLogFile = self.runner._setUpLogFile
- l = []
- def setUpLogFile():
- oldSetUpLogFile()
- l.append(self.runner._logFileObject)
- self.runner._setUpLogFile = setUpLogFile
- self.runner.run(self.test)
- self.assertEqual(len(l), 1)
- self.assertTrue(l[0].closed)
- class TrialRunnerTests(TrialRunnerTestsMixin, unittest.SynchronousTestCase):
- """
- Tests for L{runner.TrialRunner} with the feature to turn unclean errors
- into warnings disabled.
- """
- def setUp(self):
- self.stream = NativeStringIO()
- self.runner = runner.TrialRunner(CapturingReporter, stream=self.stream)
- self.test = TrialRunnerTests('test_empty')
- def test_publisher(self):
- """
- The reporter constructed by L{runner.TrialRunner} is passed
- L{twisted.python.log} as the value for the C{publisher} parameter.
- """
- result = self.runner._makeResult()
- self.assertIdentical(result._publisher, log)
- class TrialRunnerWithUncleanWarningsReporterTests(TrialRunnerTestsMixin,
- unittest.SynchronousTestCase):
- """
- Tests for the TrialRunner's interaction with an unclean-error suppressing
- reporter.
- """
- def setUp(self):
- self.stream = NativeStringIO()
- self.runner = runner.TrialRunner(CapturingReporter, stream=self.stream,
- uncleanWarnings=True)
- self.test = TrialRunnerTests('test_empty')
- class DryRunMixin(object):
- """
- Mixin for testing that 'dry run' mode works with various
- L{pyunit.TestCase} subclasses.
- """
- def setUp(self):
- self.log = []
- self.stream = NativeStringIO()
- self.runner = runner.TrialRunner(CapturingReporter,
- runner.TrialRunner.DRY_RUN,
- stream=self.stream)
- self.makeTestFixtures()
- def makeTestFixtures(self):
- """
- Set C{self.test} and C{self.suite}, where C{self.suite} is an empty
- TestSuite.
- """
- def test_empty(self):
- """
- If there are no tests, the reporter should not receive any events to
- report.
- """
- result = self.runner.run(runner.TestSuite())
- self.assertEqual(result._calls, [])
- def test_singleCaseReporting(self):
- """
- If we are running a single test, check the reporter starts, passes and
- then stops the test during a dry run.
- """
- result = self.runner.run(self.test)
- self.assertEqual(result._calls, ['startTest', 'addSuccess', 'stopTest'])
- def test_testsNotRun(self):
- """
- When we are doing a dry run, the tests should not actually be run.
- """
- self.runner.run(self.test)
- self.assertEqual(self.log, [])
- class SynchronousDryRunTests(DryRunMixin, unittest.SynchronousTestCase):
- """
- Check that 'dry run' mode works well with trial's L{SynchronousTestCase}.
- """
- def makeTestFixtures(self):
- class PyunitCase(unittest.SynchronousTestCase):
- def test_foo(self):
- pass
- self.test = PyunitCase('test_foo')
- self.suite = pyunit.TestSuite()
- class DryRunTests(DryRunMixin, unittest.SynchronousTestCase):
- """
- Check that 'dry run' mode works well with Trial tests.
- """
- def makeTestFixtures(self):
- class MockTest(unittest.TestCase):
- def test_foo(test):
- self.log.append('test_foo')
- self.test = MockTest('test_foo')
- self.suite = runner.TestSuite()
- class PyUnitDryRunTests(DryRunMixin, unittest.SynchronousTestCase):
- """
- Check that 'dry run' mode works well with stdlib unittest tests.
- """
- def makeTestFixtures(self):
- class PyunitCase(pyunit.TestCase):
- def test_foo(self):
- pass
- self.test = PyunitCase('test_foo')
- self.suite = pyunit.TestSuite()
- class RunnerTests(unittest.SynchronousTestCase):
- def setUp(self):
- self.config = trial.Options()
- # whitebox hack a reporter in, because plugins are CACHED and will
- # only reload if the FILE gets changed.
- parts = reflect.qual(CapturingReporter).split('.')
- package = '.'.join(parts[:-1])
- klass = parts[-1]
- plugins = [twisted_trial._Reporter(
- "Test Helper Reporter",
- package,
- description="Utility for unit testing.",
- longOpt="capturing",
- shortOpt=None,
- klass=klass)]
- # XXX There should really be a general way to hook the plugin system
- # for tests.
- def getPlugins(iface, *a, **kw):
- self.assertEqual(iface, IReporter)
- return plugins + list(self.original(iface, *a, **kw))
- self.original = plugin.getPlugins
- plugin.getPlugins = getPlugins
- self.standardReport = ['startTest', 'addSuccess', 'stopTest',
- 'startTest', 'addSuccess', 'stopTest',
- 'startTest', 'addSuccess', 'stopTest',
- 'startTest', 'addSuccess', 'stopTest',
- 'startTest', 'addSuccess', 'stopTest',
- 'startTest', 'addSuccess', 'stopTest',
- 'startTest', 'addSuccess', 'stopTest',
- 'startTest', 'addSuccess', 'stopTest',
- 'startTest', 'addSuccess', 'stopTest',
- 'startTest', 'addSuccess', 'stopTest']
- def tearDown(self):
- plugin.getPlugins = self.original
- def parseOptions(self, args):
- self.config.parseOptions(args)
- def getRunner(self):
- r = trial._makeRunner(self.config)
- r.stream = NativeStringIO()
- # XXX The runner should always take care of cleaning this up itself.
- # It's not clear why this is necessary. The runner always tears down
- # its log file.
- self.addCleanup(r._tearDownLogFile)
- # XXX The runner should always take care of cleaning this up itself as
- # well. It's necessary because TrialRunner._setUpTestdir might raise
- # an exception preventing Reporter.done from being run, leaving the
- # observer added by Reporter.__init__ still present in the system.
- # Something better needs to happen inside
- # TrialRunner._runWithoutDecoration to remove the need for this cludge.
- r._log = log.LogPublisher()
- return r
- def test_runner_can_get_reporter(self):
- self.parseOptions([])
- result = self.config['reporter']
- runner = self.getRunner()
- self.assertEqual(result, runner._makeResult().__class__)
- def test_runner_get_result(self):
- self.parseOptions([])
- runner = self.getRunner()
- result = runner._makeResult()
- self.assertEqual(result.__class__, self.config['reporter'])
- def test_uncleanWarningsOffByDefault(self):
- """
- By default Trial sets the 'uncleanWarnings' option on the runner to
- False. This means that dirty reactor errors will be reported as
- errors. See L{test_reporter.DirtyReactorTests}.
- """
- self.parseOptions([])
- runner = self.getRunner()
- self.assertNotIsInstance(runner._makeResult(),
- reporter.UncleanWarningsReporterWrapper)
- def test_getsUncleanWarnings(self):
- """
- Specifying '--unclean-warnings' on the trial command line will cause
- reporters to be wrapped in a device which converts unclean errors to
- warnings. See L{test_reporter.DirtyReactorTests} for implications.
- """
- self.parseOptions(['--unclean-warnings'])
- runner = self.getRunner()
- self.assertIsInstance(runner._makeResult(),
- reporter.UncleanWarningsReporterWrapper)
- def test_runner_working_directory(self):
- self.parseOptions(['--temp-directory', 'some_path'])
- runner = self.getRunner()
- self.assertEqual(runner.workingDirectory, 'some_path')
- def test_concurrentImplicitWorkingDirectory(self):
- """
- If no working directory is explicitly specified and the default
- working directory is in use by another runner, L{TrialRunner.run}
- selects a different default working directory to use.
- """
- self.parseOptions([])
- # Make sure we end up with the same working directory after this test
- # as we had before it.
- self.addCleanup(os.chdir, os.getcwd())
- # Make a new directory and change into it. This isolates us from state
- # that other tests might have dumped into this process's temp
- # directory.
- runDirectory = FilePath(self.mktemp())
- runDirectory.makedirs()
- os.chdir(runDirectory.path)
- firstRunner = self.getRunner()
- secondRunner = self.getRunner()
- where = {}
- class ConcurrentCase(unittest.SynchronousTestCase):
- def test_first(self):
- """
- Start a second test run which will have a default working
- directory which is the same as the working directory of the
- test run already in progress.
- """
- # Change the working directory to the value it had before this
- # test suite was started.
- where['concurrent'] = subsequentDirectory = os.getcwd()
- os.chdir(runDirectory.path)
- self.addCleanup(os.chdir, subsequentDirectory)
- secondRunner.run(ConcurrentCase('test_second'))
- def test_second(self):
- """
- Record the working directory for later analysis.
- """
- where['record'] = os.getcwd()
- result = firstRunner.run(ConcurrentCase('test_first'))
- bad = result.errors + result.failures
- if bad:
- self.fail(bad[0][1])
- self.assertEqual(
- where, {
- 'concurrent': runDirectory.child('_trial_temp').path,
- 'record': runDirectory.child('_trial_temp-1').path})
- def test_concurrentExplicitWorkingDirectory(self):
- """
- If a working directory which is already in use is explicitly specified,
- L{TrialRunner.run} raises L{_WorkingDirectoryBusy}.
- """
- self.parseOptions(['--temp-directory', os.path.abspath(self.mktemp())])
- initialDirectory = os.getcwd()
- self.addCleanup(os.chdir, initialDirectory)
- firstRunner = self.getRunner()
- secondRunner = self.getRunner()
- class ConcurrentCase(unittest.SynchronousTestCase):
- def test_concurrent(self):
- """
- Try to start another runner in the same working directory and
- assert that it raises L{_WorkingDirectoryBusy}.
- """
- self.assertRaises(
- util._WorkingDirectoryBusy,
- secondRunner.run, ConcurrentCase('test_failure'))
- def test_failure(self):
- """
- Should not be called, always fails.
- """
- self.fail("test_failure should never be called.")
- result = firstRunner.run(ConcurrentCase('test_concurrent'))
- bad = result.errors + result.failures
- if bad:
- self.fail(bad[0][1])
- def test_runner_normal(self):
- self.parseOptions(['--temp-directory', self.mktemp(),
- '--reporter', 'capturing',
- 'twisted.trial.test.sample'])
- my_runner = self.getRunner()
- loader = runner.TestLoader()
- suite = loader.loadByName('twisted.trial.test.sample', True)
- result = my_runner.run(suite)
- self.assertEqual(self.standardReport, result._calls)
- def runSampleSuite(self, my_runner):
- loader = runner.TestLoader()
- suite = loader.loadByName('twisted.trial.test.sample', True)
- return my_runner.run(suite)
- def test_runnerDebug(self):
- """
- Trial uses its debugger if the `--debug` option is passed.
- """
- self.parseOptions(['--reporter', 'capturing',
- '--debug', 'twisted.trial.test.sample'])
- my_runner = self.getRunner()
- debugger = my_runner.debugger = CapturingDebugger()
- result = self.runSampleSuite(my_runner)
- self.assertEqual(self.standardReport, result._calls)
- self.assertEqual(['runcall'], debugger._calls)
- def test_runnerDebuggerDefaultsToPdb(self):
- """
- Trial uses pdb if no debugger is specified by `--debugger`
- """
- self.parseOptions(['--debug', 'twisted.trial.test.sample'])
- pdbrcFile = FilePath("pdbrc")
- pdbrcFile.touch()
- self.runcall_called = False
- def runcall(pdb, suite, result):
- self.runcall_called = True
- self.patch(pdb.Pdb, "runcall", runcall)
- self.runSampleSuite(self.getRunner())
- self.assertTrue(self.runcall_called)
- def test_runnerDebuggerWithExplicitlyPassedPdb(self):
- """
- Trial uses pdb if pdb is passed explicitly to the `--debugger` arg.
- """
- self.parseOptions([
- '--reporter', 'capturing',
- '--debugger', 'pdb',
- '--debug', 'twisted.trial.test.sample',
- ])
- self.runcall_called = False
- def runcall(pdb, suite, result):
- self.runcall_called = True
- self.patch(pdb.Pdb, "runcall", runcall)
- self.runSampleSuite(self.getRunner())
- self.assertTrue(self.runcall_called)
- cdebugger = CapturingDebugger()
- def test_runnerDebugger(self):
- """
- Trial uses specified debugger if the debugger is available.
- """
- self.parseOptions([
- '--reporter', 'capturing',
- '--debugger',
- 'twisted.trial.test.test_runner.RunnerTests.cdebugger',
- '--debug',
- 'twisted.trial.test.sample',
- ])
- my_runner = self.getRunner()
- result = self.runSampleSuite(my_runner)
- self.assertEqual(self.standardReport, result._calls)
- self.assertEqual(['runcall'], my_runner.debugger._calls)
- def test_exitfirst(self):
- """
- If trial was passed the C{--exitfirst} option, the constructed test
- result object is wrapped with L{reporter._ExitWrapper}.
- """
- self.parseOptions(["--exitfirst"])
- runner = self.getRunner()
- result = runner._makeResult()
- self.assertIsInstance(result, reporter._ExitWrapper)
- class TrialSuiteTests(unittest.SynchronousTestCase):
- def test_imports(self):
- # FIXME, HTF do you test the reactor can be cleaned up ?!!!
- namedAny('twisted.trial.runner.TrialSuite')
- class UntilFailureTests(unittest.SynchronousTestCase):
- class FailAfter(pyunit.TestCase):
- """
- A test case that fails when run 3 times in a row.
- """
- count = []
- def test_foo(self):
- self.count.append(None)
- if len(self.count) == 3:
- self.fail('Count reached 3')
- def setUp(self):
- UntilFailureTests.FailAfter.count = []
- self.test = UntilFailureTests.FailAfter('test_foo')
- self.stream = NativeStringIO()
- self.runner = runner.TrialRunner(reporter.Reporter, stream=self.stream)
- def test_runUntilFailure(self):
- """
- Test that the runUntilFailure method of the runner actually fail after
- a few runs.
- """
- result = self.runner.runUntilFailure(self.test)
- self.assertEqual(result.testsRun, 1)
- self.assertFalse(result.wasSuccessful())
- self.assertEqual(self._getFailures(result), 1)
- def _getFailures(self, result):
- """
- Get the number of failures that were reported to a result.
- """
- return len(result.failures)
- def test_runUntilFailureDecorate(self):
- """
- C{runUntilFailure} doesn't decorate the tests uselessly: it does it one
- time when run starts, but not at each turn.
- """
- decorated = []
- def decorate(test, interface):
- decorated.append((test, interface))
- return test
- self.patch(unittest, "decorate", decorate)
- result = self.runner.runUntilFailure(self.test)
- self.assertEqual(result.testsRun, 1)
- self.assertEqual(len(decorated), 1)
- self.assertEqual(decorated, [(self.test, ITestCase)])
- def test_runUntilFailureForceGCDecorate(self):
- """
- C{runUntilFailure} applies the force-gc decoration after the standard
- L{ITestCase} decoration, but only one time.
- """
- decorated = []
- def decorate(test, interface):
- decorated.append((test, interface))
- return test
- self.patch(unittest, "decorate", decorate)
- self.runner._forceGarbageCollection = True
- result = self.runner.runUntilFailure(self.test)
- self.assertEqual(result.testsRun, 1)
- self.assertEqual(len(decorated), 2)
- self.assertEqual(decorated,
- [(self.test, ITestCase),
- (self.test, _ForceGarbageCollectionDecorator)])
- class UncleanUntilFailureTests(UntilFailureTests):
- """
- Test that the run-until-failure feature works correctly with the unclean
- error suppressor.
- """
- def setUp(self):
- UntilFailureTests.setUp(self)
- self.runner = runner.TrialRunner(reporter.Reporter, stream=self.stream,
- uncleanWarnings=True)
- def _getFailures(self, result):
- """
- Get the number of failures that were reported to a result that
- is wrapped in an UncleanFailureWrapper.
- """
- return len(result._originalReporter.failures)
- class BreakingSuite(runner.TestSuite):
- """
- A L{TestSuite} that logs an error when it is run.
- """
- def run(self, result):
- try:
- raise RuntimeError("error that occurs outside of a test")
- except RuntimeError:
- log.err(failure.Failure())
- class LoggedErrorsTests(unittest.SynchronousTestCase):
- """
- It is possible for an error generated by a test to be logged I{outside} of
- any test. The log observers constructed by L{TestCase} won't catch these
- errors. Here we try to generate such errors and ensure they are reported to
- a L{TestResult} object.
- """
- def tearDown(self):
- self.flushLoggedErrors(RuntimeError)
- def test_construct(self):
- """
- Check that we can construct a L{runner.LoggedSuite} and that it
- starts empty.
- """
- suite = runner.LoggedSuite()
- self.assertEqual(suite.countTestCases(), 0)
- def test_capturesError(self):
- """
- Chek that a L{LoggedSuite} reports any logged errors to its result.
- """
- result = reporter.TestResult()
- suite = runner.LoggedSuite([BreakingSuite()])
- suite.run(result)
- self.assertEqual(len(result.errors), 1)
- self.assertEqual(result.errors[0][0].id(), runner.NOT_IN_TEST)
- self.assertTrue(result.errors[0][1].check(RuntimeError))
- class TestHolderTests(unittest.SynchronousTestCase):
- def setUp(self):
- self.description = "description"
- self.holder = runner.TestHolder(self.description)
- def test_holder(self):
- """
- Check that L{runner.TestHolder} takes a description as a parameter
- and that this description is returned by the C{id} and
- C{shortDescription} methods.
- """
- self.assertEqual(self.holder.id(), self.description)
- self.assertEqual(self.holder.shortDescription(), self.description)
- def test_holderImplementsITestCase(self):
- """
- L{runner.TestHolder} implements L{ITestCase}.
- """
- self.assertIdentical(self.holder, ITestCase(self.holder))
- self.assertTrue(
- verifyObject(ITestCase, self.holder),
- "%r claims to provide %r but does not do so correctly."
- % (self.holder, ITestCase))
- def test_runsWithStandardResult(self):
- """
- A L{runner.TestHolder} can run against the standard Python
- C{TestResult}.
- """
- result = pyunit.TestResult()
- self.holder.run(result)
- self.assertTrue(result.wasSuccessful())
- self.assertEqual(1, result.testsRun)
- class ErrorHolderTestsMixin(object):
- """
- This mixin defines test methods which can be applied to a
- L{runner.ErrorHolder} constructed with either a L{Failure} or a
- C{exc_info}-style tuple.
- Subclass this and implement C{setUp} to create C{self.holder} referring to a
- L{runner.ErrorHolder} instance and C{self.error} referring to a L{Failure}
- which the holder holds.
- """
- exceptionForTests = ZeroDivisionError('integer division or modulo by zero')
- class TestResultStub(object):
- """
- Stub for L{TestResult}.
- """
- def __init__(self):
- self.errors = []
- def startTest(self, test):
- pass
- def stopTest(self, test):
- pass
- def addError(self, test, error):
- self.errors.append((test, error))
- def test_runsWithStandardResult(self):
- """
- A L{runner.ErrorHolder} can run against the standard Python
- C{TestResult}.
- """
- result = pyunit.TestResult()
- self.holder.run(result)
- self.assertFalse(result.wasSuccessful())
- self.assertEqual(1, result.testsRun)
- def test_run(self):
- """
- L{runner.ErrorHolder} adds an error to the result when run.
- """
- self.holder.run(self.result)
- self.assertEqual(
- self.result.errors,
- [(self.holder, (self.error.type, self.error.value, self.error.tb))])
- def test_call(self):
- """
- L{runner.ErrorHolder} adds an error to the result when called.
- """
- self.holder(self.result)
- self.assertEqual(
- self.result.errors,
- [(self.holder, (self.error.type, self.error.value, self.error.tb))])
- def test_countTestCases(self):
- """
- L{runner.ErrorHolder.countTestCases} always returns 0.
- """
- self.assertEqual(self.holder.countTestCases(), 0)
- def test_repr(self):
- """
- L{runner.ErrorHolder.__repr__} returns a string describing the error it
- holds.
- """
- self.assertEqual(repr(self.holder),
- "<ErrorHolder description='description' "
- "error=ZeroDivisionError('integer division or modulo by zero',)>")
- class FailureHoldingErrorHolderTests(ErrorHolderTestsMixin, TestHolderTests):
- """
- Tests for L{runner.ErrorHolder} behaving similarly to L{runner.TestHolder}
- when constructed with a L{Failure} representing its error.
- """
- def setUp(self):
- self.description = "description"
- # make a real Failure so we can construct ErrorHolder()
- try:
- raise self.exceptionForTests
- except ZeroDivisionError:
- self.error = failure.Failure()
- self.holder = runner.ErrorHolder(self.description, self.error)
- self.result = self.TestResultStub()
- class ExcInfoHoldingErrorHolderTests(ErrorHolderTestsMixin, TestHolderTests):
- """
- Tests for L{runner.ErrorHolder} behaving similarly to L{runner.TestHolder}
- when constructed with a C{exc_info}-style tuple representing its error.
- """
- def setUp(self):
- self.description = "description"
- # make a real Failure so we can construct ErrorHolder()
- try:
- raise self.exceptionForTests
- except ZeroDivisionError:
- exceptionInfo = sys.exc_info()
- self.error = failure.Failure()
- self.holder = runner.ErrorHolder(self.description, exceptionInfo)
- self.result = self.TestResultStub()
- class MalformedMethodTests(unittest.SynchronousTestCase):
- """
- Test that trial manages when test methods don't have correct signatures.
- """
- class ContainMalformed(pyunit.TestCase):
- """
- This TestCase holds malformed test methods that trial should handle.
- """
- def test_foo(self, blah):
- pass
- def test_bar():
- pass
- test_spam = defer.inlineCallbacks(test_bar)
- def _test(self, method):
- """
- Wrapper for one of the test method of L{ContainMalformed}.
- """
- stream = NativeStringIO()
- trialRunner = runner.TrialRunner(reporter.Reporter, stream=stream)
- test = MalformedMethodTests.ContainMalformed(method)
- result = trialRunner.run(test)
- self.assertEqual(result.testsRun, 1)
- self.assertFalse(result.wasSuccessful())
- self.assertEqual(len(result.errors), 1)
- def test_extraArg(self):
- """
- Test when the method has extra (useless) arguments.
- """
- self._test('test_foo')
- def test_noArg(self):
- """
- Test when the method doesn't have even self as argument.
- """
- self._test('test_bar')
- def test_decorated(self):
- """
- Test a decorated method also fails.
- """
- self._test('test_spam')
- class DestructiveTestSuiteTests(unittest.SynchronousTestCase):
- """
- Test for L{runner.DestructiveTestSuite}.
- """
- def test_basic(self):
- """
- Thes destructive test suite should run the tests normally.
- """
- called = []
- class MockTest(pyunit.TestCase):
- def test_foo(test):
- called.append(True)
- test = MockTest('test_foo')
- result = reporter.TestResult()
- suite = runner.DestructiveTestSuite([test])
- self.assertEqual(called, [])
- suite.run(result)
- self.assertEqual(called, [True])
- self.assertEqual(suite.countTestCases(), 0)
- def test_shouldStop(self):
- """
- Test the C{shouldStop} management: raising a C{KeyboardInterrupt} must
- interrupt the suite.
- """
- called = []
- class MockTest(unittest.TestCase):
- def test_foo1(test):
- called.append(1)
- def test_foo2(test):
- raise KeyboardInterrupt()
- def test_foo3(test):
- called.append(2)
- result = reporter.TestResult()
- loader = runner.TestLoader()
- loader.suiteFactory = runner.DestructiveTestSuite
- suite = loader.loadClass(MockTest)
- self.assertEqual(called, [])
- suite.run(result)
- self.assertEqual(called, [1])
- # The last test shouldn't have been run
- self.assertEqual(suite.countTestCases(), 1)
- def test_cleanup(self):
- """
- Checks that the test suite cleanups its tests during the run, so that
- it ends empty.
- """
- class MockTest(pyunit.TestCase):
- def test_foo(test):
- pass
- test = MockTest('test_foo')
- result = reporter.TestResult()
- suite = runner.DestructiveTestSuite([test])
- self.assertEqual(suite.countTestCases(), 1)
- suite.run(result)
- self.assertEqual(suite.countTestCases(), 0)
- class RunnerDeprecationTests(unittest.SynchronousTestCase):
- class FakeReporter(reporter.Reporter):
- """
- Fake reporter that does *not* implement done() but *does* implement
- printErrors, separator, printSummary, stream, write and writeln
- without deprecations.
- """
- done = None
- separator = None
- stream = None
- def printErrors(self, *args):
- pass
- def printSummary(self, *args):
- pass
- def write(self, *args):
- pass
- def writeln(self, *args):
- pass
- def test_reporterDeprecations(self):
- """
- The runner emits a warning if it is using a result that doesn't
- implement 'done'.
- """
- trialRunner = runner.TrialRunner(None)
- result = self.FakeReporter()
- trialRunner._makeResult = lambda: result
- def f():
- # We have to use a pyunit test, otherwise we'll get deprecation
- # warnings about using iterate() in a test.
- trialRunner.run(pyunit.TestCase('id'))
- f()
- warnings = self.flushWarnings([self.test_reporterDeprecations])
- self.assertEqual(warnings[0]['category'], DeprecationWarning)
- self.assertEqual(warnings[0]['message'],
- "%s should implement done() but doesn't. Falling back to "
- "printErrors() and friends." % reflect.qual(result.__class__))
- self.assertTrue(__file__.startswith(warnings[0]['filename']))
- self.assertEqual(len(warnings), 1)
- class QualifiedNameWalkerTests(unittest.SynchronousTestCase):
- """
- Tests for L{twisted.trial.runner._qualNameWalker}.
- """
- def test_walksDownPath(self):
- """
- C{_qualNameWalker} is a generator that, when given a Python qualified
- name, yields that name, and then the parent of that name, and so forth,
- along with a list of the tried components, in a 2-tuple.
- """
- walkerResults = list(runner._qualNameWalker("walker.texas.ranger"))
- self.assertEqual(walkerResults,
- [("walker.texas.ranger", []),
- ("walker.texas", ["ranger"]),
- ("walker", ["texas", "ranger"])])
- class TrialMainDoesNothingTests(unittest.SynchronousTestCase):
- """
- Importing L{twisted.trial.__main__} will not run the script
- unless it is actually C{__main__}.
- """
- def test_importDoesNothing(self):
- """
- If we import L{twisted.trial.__main__}, it should do nothing.
- """
- # We shouldn't suddenly drop into a script when we import this!
- __import__('twisted.trial.__main__')
|