Ticket #5787: toptobottom-3.patch

File toptobottom-3.patch, 11.2 KB (added by Julian Berman, 9 years ago)
  • doc/core/man/trial.1

    diff --git a/doc/core/man/trial.1 b/doc/core/man/trial.1
    index 1448463..6671282 100644
    a b the default, except it makes tests run about ten times slower. 
    116116\fB-h\fR, \fB--help\fR
    117117Print a usage message to standard output, then exit.
    118118.TP
     119\fB--help-order\fR
     120Print a list of possible orders that TestCase test methods can be run in, then
     121exit. The orders can be used with the --order option described below.
     122.TP
    119123\fB--help-reporters\fR
    120124Print a list of valid reporters to standard output, then exit. Reporters can
    121125be selected with the --reporter option described below.
    every subpackage. Unless, that is, you specify this option. 
    140144Don't automatically jump into debugger for post-mortem analysis of
    141145exceptions.  Only usable in conjunction with --debug.
    142146.TP
     147\fB--order\fR \fIorder\fR
     148Specify what order to run the individual test methods within the given
     149TestCases. By default, they are run alphabetically. See --help-order for a list
     150of other valid values.
     151.TP
    143152\fB--profile\fR
    144153Run tests under the Python profiler.
    145154.TP
  • twisted/scripts/trial.py

    diff --git a/twisted/scripts/trial.py b/twisted/scripts/trial.py
    index f317841..2b411e0 100644
    a b  
    44# See LICENSE for details.
    55
    66
    7 import sys, os, random, gc, pdb, time, warnings
     7from __future__ import print_function
     8import sys, os, random, gc, pdb, time, warnings, inspect
    89
    910from twisted.internet import defer
    1011from twisted.application import app
    def _reporterAction(): 
    9596
    9697
    9798
     99# orders which can be passed to trial --order
     100_runOrders = [
     101    ("alphabetical",
     102     "alphabetical order for test methods, arbitrary order for test cases"),
     103    ("toptobottom",
     104     "attempt to run test cases and methods in the order they were defined"),
     105]
     106
     107
     108
    98109class _BasicOptions(object):
    99110    """
    100111    Basic options shared between trial and its local workers.
    class _BasicOptions(object): 
    107118
    108119    optFlags = [["help", "h"],
    109120                ["no-recurse", "N", "Don't recurse into packages"],
     121                ['help-orders', None, "Help on available test running orders"],
    110122                ['help-reporters', None,
    111123                 "Help on available output plugins (reporters)"],
    112124                ["rterrors", "e", "realtime errors, print out tracebacks as "
    class _BasicOptions(object): 
    118130                ]
    119131
    120132    optParameters = [
     133        ["order", "o", None, "Specify what order to run test cases and methods"
     134         ". See --help-orders for more info."],
    121135        ["random", "z", None,
    122136         "Run tests in random order using the specified seed"],
    123137        ['temp-directory', None, '_trial_temp',
    class _BasicOptions(object): 
    127141         'more info.']]
    128142
    129143    compData = usage.Completions(
    130         optActions={"reporter": _reporterAction,
     144        optActions={"order": usage.CompleteList(
     145                        name for name, _ in _runOrders),
     146                    "reporter": _reporterAction,
    131147                    "logfile": usage.CompleteFiles(descr="log file name"),
    132148                    "random": usage.Completer(descr="random seed")},
    133149        extraActions=[usage.CompleteFiles(
    class _BasicOptions(object): 
    150166        """
    151167        coverdir = 'coverage'
    152168        result = FilePath(self['temp-directory']).child(coverdir)
    153         print "Setting coverage directory to %s." % (result.path,)
     169        print("Setting coverage directory to %s." % (result.path,))
    154170        return result
    155171
    156172
    class _BasicOptions(object): 
    197213        sys.settrace(spewer)
    198214
    199215
     216    def opt_help_orders(self):
     217        synopsis = ("Trial can attempt to run test cases and their methods in "
     218                    "a few different\n orders. You can select any of the "
     219                    "following options using --order=<foo>.\n")
     220
     221        print(synopsis)
     222        for name, description in _runOrders:
     223            print('   ', name, '\t', description)
     224        sys.exit(0)
     225
     226
    200227    def opt_help_reporters(self):
    201228        synopsis = ("Trial's output can be customized using plugins called "
    202229                    "Reporters. You can\nselect any of the following "
    203230                    "reporters using --reporter=<foo>\n")
    204         print synopsis
     231        print(synopsis)
    205232        for p in plugin.getPlugins(itrial.IReporter):
    206             print '   ', p.longOpt, '\t', p.description
    207         print
     233            print('   ', p.longOpt, '\t', p.description)
    208234        sys.exit(0)
    209235
    210236
    class _BasicOptions(object): 
    229255                "tbformat must be 'plain', 'emacs', or 'cgitb'.")
    230256
    231257
     258    def opt_order(self, order):
     259        """
     260        Run the tests in the given order.
     261
     262        """
     263
     264        if order == "toptobottom":
     265            self['order'] = _maybeFindSourceLine
     266        elif order == "alphabetical":
     267            self['order'] = runner.name
     268        else:
     269            orders = ", ".join(repr(order) for order, _ in _runOrders)
     270            raise usage.UsageError("order must be one of " + orders)
     271
     272
    232273    def opt_recursionlimit(self, arg):
    233274        """
    234275        see sys.setrecursionlimit()
    def _getSuite(config): 
    404445
    405446
    406447
     448def _maybeFindSourceLine(thing):
     449    """
     450    Try to find the source line of the given test thing.
     451
     452    """
     453
     454    method = getattr(thing, "_testMethodName", None)
     455    if method is not None:
     456        thing = getattr(thing, method)
     457
     458    try:
     459        return inspect.getsourcelines(thing)[1]
     460    except (IOError, TypeError):
     461        # either thing is a module, which raised a TypeError, or the file
     462        # couldn't be read
     463        return -1
     464
     465
     466
    407467def _getLoader(config):
    408468    loader = runner.TestLoader()
    409469    if config['random']:
    410470        randomer = random.Random()
    411471        randomer.seed(config['random'])
    412472        loader.sorter = lambda x : randomer.random()
    413         print 'Running tests shuffled with seed %d\n' % config['random']
     473        print('Running tests shuffled with seed %d\n' % config['random'])
     474    elif config['order']:
     475        loader.sorter = config['order']
    414476    if not config['until-failure']:
    415477        loader.suiteFactory = runner.DestructiveTestSuite
    416478    return loader
    def _wrappedPdb(): 
    426488    try:
    427489        import readline
    428490    except ImportError:
    429         print "readline module not available"
     491        print("readline module not available")
    430492        sys.exc_clear()
    431493    for path in ('.pdbrc', 'pdbrc'):
    432494        if os.path.exists(path):
  • twisted/topfiles/5787.feature

    diff --git a/twisted/topfiles/5787.feature b/twisted/topfiles/5787.feature
    index e69de29..7a7d97b 100644
    a b  
     1trial now accepts a --order option that specifies what order to run TestCase methods in.
  • twisted/trial/test/ordertests.py

    diff --git a/twisted/trial/test/ordertests.py b/twisted/trial/test/ordertests.py
    index e69de29..bee80b4 100644
    a b  
     1# -*- test-case-name: twisted.trial.test.test_script -*-
     2# Copyright (c) Twisted Matrix Laboratories.
     3# See LICENSE for details.
     4
     5"""
     6Tests for handling of trial's --order option.
     7"""
     8
     9from twisted.trial import unittest
     10
     11
     12class FooTest(unittest.TestCase):
     13    """
     14    Used to make assertions about the order its tests will be run in.
     15    """
     16
     17    def test_first(self):
     18        pass
     19
     20
     21    def test_second(self):
     22        pass
     23
     24
     25    def test_third(self):
     26        pass
     27
     28
     29    def test_fourth(self):
     30        pass
     31
     32
     33
     34class BazTest(unittest.TestCase):
     35    def test_baz(self):
     36        pass
     37
     38
     39
     40class BarTest(unittest.TestCase):
     41    def test_bar(self):
     42        pass
  • twisted/trial/test/test_script.py

    diff --git a/twisted/trial/test/test_script.py b/twisted/trial/test/test_script.py
    index d92d9f8..13b55e3 100644
    a b class TestRun(unittest.TestCase): 
    594594            self.assertIn("foo", str(e))
    595595        else:
    596596            self.fail("Should have exited due to non-existent debugger!")
     597
     598
     599
     600class OrderTests(unittest.TestCase):
     601    """
     602    Tests for the --order option.
     603    """
     604
     605
     606    def setUp(self):
     607        self.config = trial.Options()
     608
     609
     610    def test_alphabetical(self):
     611        """
     612        --order=alphabetical causes trial to run tests alphabetically within
     613        each test case.
     614        """
     615
     616        self.config.parseOptions([
     617            "--order", "alphabetical",
     618            "twisted.trial.test.ordertests.FooTest"])
     619
     620        loader = trial._getLoader(self.config)
     621        suite = loader.loadByNames(self.config['tests'])
     622
     623        self.assertEqual(
     624            testNames(suite), [
     625            'twisted.trial.test.ordertests.FooTest.test_first',
     626            'twisted.trial.test.ordertests.FooTest.test_fourth',
     627            'twisted.trial.test.ordertests.FooTest.test_second',
     628            'twisted.trial.test.ordertests.FooTest.test_third'])
     629
     630
     631    def test_toptobottom(self):
     632        """
     633        --order=toptobottom causes trial to run test methods within a given
     634        test case from top to bottom as they are defined in the body of the
     635        class.
     636        """
     637
     638        self.config.parseOptions([
     639            "--order", "toptobottom",
     640            "twisted.trial.test.ordertests.FooTest"])
     641
     642        loader = trial._getLoader(self.config)
     643        suite = loader.loadByNames(self.config['tests'])
     644
     645        self.assertEqual(
     646            testNames(suite), [
     647            'twisted.trial.test.ordertests.FooTest.test_first',
     648            'twisted.trial.test.ordertests.FooTest.test_second',
     649            'twisted.trial.test.ordertests.FooTest.test_third',
     650            'twisted.trial.test.ordertests.FooTest.test_fourth'])
     651
     652
     653    def test_toptobottomModule(self):
     654        """
     655        --order=toptobottom causes trial to run test classes within a given
     656        module from top to bottom as they are defined in the module's source.
     657        """
     658
     659        self.config.parseOptions([
     660            "--order", "toptobottom", "twisted.trial.test.ordertests"])
     661        loader = trial._getLoader(self.config)
     662        suite = loader.loadByNames(self.config['tests'])
     663
     664        self.assertEqual(
     665            testNames(suite), [
     666            'twisted.trial.test.ordertests.FooTest.test_first',
     667            'twisted.trial.test.ordertests.FooTest.test_second',
     668            'twisted.trial.test.ordertests.FooTest.test_third',
     669            'twisted.trial.test.ordertests.FooTest.test_fourth',
     670            'twisted.trial.test.ordertests.BazTest.test_baz',
     671            'twisted.trial.test.ordertests.BarTest.test_bar'])
     672
     673
     674
     675class HelpOrderTests(unittest.TestCase):
     676    """
     677    Tests for the --help-orders flag.
     678    """
     679
     680
     681    def test_help_ordersPrintsSynopsisAndQuits(self):
     682        """
     683        --help-orders prints each of the available orders and then exits.
     684        """
     685
     686        self.status = None
     687        self.patch(
     688            trial.sys, "exit", lambda status: setattr(self, "status", status))
     689        self.patch(sys, "stdout", StringIO.StringIO())
     690
     691        trial.Options().parseOptions(["--help-orders"])
     692
     693        for orderName, orderDesc in trial._runOrders:
     694            self.assertIn(orderName, sys.stdout.getvalue())
     695            self.assertIn(orderDesc, sys.stdout.getvalue())
     696        self.assertEqual(self.status, 0)