diff --git a/cricket/unittest/discoverer.py b/cricket/unittest/discoverer.py index c408eea..fadbfc7 100644 --- a/cricket/unittest/discoverer.py +++ b/cricket/unittest/discoverer.py @@ -25,37 +25,41 @@ def consume(iterable): except: yield item -class PyTestDiscoverer: - def __init__(self): +class PyTestDiscoverer: + def __init__(self, start='.', pattern='test*.py', top=None): + self.start = start + self.pattern = pattern + self.top = top self.collected_tests = [] - def __str__(self): ''' Builds the dotted namespace expected by cricket ''' - resultstr = '\n'.join(self.collected_tests) - return resultstr.strip() - def collect_tests(self): ''' Collect a list of potentially runnable tests ''' - loader = unittest.TestLoader() - suite = loader.discover('.') + suite = loader.discover(self.start, self.pattern, self.top) flatresults = list(consume(suite)) named = [r.id() for r in flatresults] self.collected_tests = named - + if __name__ == '__main__': + from argparse import ArgumentParser + from cricket.unittest.options import add_arguments + + parser = ArgumentParser() + add_arguments(parser) + options = parser.parse_args() - PTD = PyTestDiscoverer() + PTD = PyTestDiscoverer(options.start, options.pattern, options.top) PTD.collect_tests() - print str(PTD) \ No newline at end of file + print str(PTD) diff --git a/cricket/unittest/executor.py b/cricket/unittest/executor.py index 9271cc2..19fba7d 100644 --- a/cricket/unittest/executor.py +++ b/cricket/unittest/executor.py @@ -6,6 +6,7 @@ Its main API is the command line, but it's just as sensible to call into it. See __main__ for usage ''' + import argparse import unittest @@ -24,16 +25,25 @@ class PyTestExecutor(object): initiated by the top-level Executor class ''' - def __init__(self): - - # Allows the executor to run a specified list of tests - self.specified_list = None + def __init__(self, start='.', pattern='test*.py', top=None, test_names=None): + self.start = start + self.pattern = pattern + self.top = top + self.test_names = test_names - def run_only(self, specified_list): - self.specified_list = specified_list + def load_suite(self): + # Use explicit test_names if provided, other wise fall back to + # discovery equivalent to the discoverer. + loader = unittest.TestLoader() + if self.test_names: + suite = unittest.TestSuite() + for name in self.test_names: + suite.addTest(loader.loadTestsFromName(name)) + else: + suite = loader.discover(self.start, self.pattern, self.top) + return suite def stream_suite(self, suite): - pipes.PipedTestRunner().run(suite) def stream_results(self): @@ -42,16 +52,8 @@ def stream_results(self): 2.) Otherwise fetch specific tests 3.) Execute-and-stream ''' - - loader = unittest.TestLoader() - - if not self.specified_list: - suite = loader.discover('.') - self.stream_suite(suite) - else: - for module in self.specified_list: - suite = loader.loadTestsFromName(module) - self.stream_suite(suite) + suite = self.load_suite() + self.stream_suite(suite) class PyTestCoverageExecutor(PyTestExecutor): @@ -70,18 +72,26 @@ def stream_suite(self, suite): parser = argparse.ArgumentParser() parser.add_argument("--coverage", help="Generate coverage data for the test run", action="store_true") - parser.add_argument( - 'labels', nargs=argparse.REMAINDER, - help='Test labels to run.' - ) + parser.add_argument('-t', '--test-names', action='store_true', + help='Interpret arguments as test names.') + parser.add_argument('labels', nargs=argparse.REMAINDER, + help='Test labels to run.') options = parser.parse_args() + options.start = '.' + options.pattern = 'test*.py' + options.top = None if options.coverage: - PTE = PyTestCoverageExecutor() + cls = PyTestCoverageExecutor + else: + cls = PyTestExecutor + + if options.test_names: + executor = cls(test_names=options.labels) else: - PTE = PyTestExecutor() + for name, value in zip(('start', 'pattern', 'top'), options.labels): + setattr(options, name, value) + executor = cls(options.start, options.pattern, options.top) - if options.labels: - PTE.run_only(options.labels) - PTE.stream_results() + executor.stream_results() diff --git a/cricket/unittest/model.py b/cricket/unittest/model.py index cd7a74c..d0ef553 100644 --- a/cricket/unittest/model.py +++ b/cricket/unittest/model.py @@ -1,19 +1,38 @@ import sys from cricket.model import Project +import cricket.unittest.options + class UnittestProject(Project): def __init__(self, options=None): + self.start = getattr(options, 'start', '.') + self.pattern = getattr(options, 'pattern', 'test*py') + self.top = getattr(options, 'top', None) super(UnittestProject, self).__init__() + @classmethod + def add_arguments(cls, parser): + cricket.unittest.options.add_arguments(parser) + def discover_commandline(self): "Command line: Discover all available tests in a project." - return [sys.executable, '-m', 'cricket.unittest.discoverer'] + args = [sys.executable, '-m', 'cricket.unittest.discoverer', + self.start, self.pattern] + if self.top is not None: + args.append(self.top) + return args def execute_commandline(self, labels): "Return the command line to execute the specified test labels" args = [sys.executable, '-m', 'cricket.unittest.executor'] if self.coverage: args.append('--coverage') - return args + labels \ No newline at end of file + if labels: + args.extend(['-t'] + labels) + else: + args.extend([self.start, self.pattern]) + if self.top is not None: + args.append(self.top) + return args diff --git a/cricket/unittest/options.py b/cricket/unittest/options.py new file mode 100644 index 0000000..6752ae5 --- /dev/null +++ b/cricket/unittest/options.py @@ -0,0 +1,15 @@ +""" +argparse options common to discoverer, executor and model. +""" + + +def add_arguments(parser): + """ + Add unittest discovery settings to the argument parser. + """ + parser.add_argument('start', nargs='?', default='.', + help="Directory to start discovery ('.' default)") + parser.add_argument('pattern', nargs='?', default='test*.py', + help="Pattern to match tests ('test*.py' default)") + parser.add_argument('top', nargs='?', default=None, + help='Top level directory of project (defaults to start directory)') diff --git a/docs/index.rst b/docs/index.rst index 75614a5..a6f0042 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -51,6 +51,18 @@ In a unittest project, install cricket, and then run it:: This will pop up a GUI window. Hit "Run all", and watch your test suite execute. +``cricket-unittest`` also accepts the 'discover' arguments for ``unittest``:: + + usage: cricket-unittest [-h] [--version] [start] [pattern] [top] + +(See also ``cricket-unittest -h``.) + +For example this will find tests inside packages. For example, if you have +``simplejson`` installed, you can run the tests present in +``simplejson.tests``:: + + $ cricket-unittest simplejson + Problems under Ubuntu ~~~~~~~~~~~~~~~~~~~~~ diff --git a/tests/test_unit_integration.py b/tests/test_unit_integration.py index 2a9113e..6837f86 100644 --- a/tests/test_unit_integration.py +++ b/tests/test_unit_integration.py @@ -33,7 +33,7 @@ def test_labels(self): ''' labels = ['tests.test_unit_integration.TestCollection'] - cmdline = ['python', '-m', 'cricket.unittest.executor'] + labels + cmdline = ['python', '-m', 'cricket.unittest.executor', '-t'] + labels runner = subprocess.Popen( cmdline,