← Back to team overview

testtools-dev team mailing list archive

[Merge] lp:~jml/testtools/distutils-integration-693773 into lp:testtools

 

Jonathan Lange has proposed merging lp:~jml/testtools/distutils-integration-693773 into lp:testtools.

Requested reviews:
  testtools developers (testtools-dev)
Related bugs:
  #693773 [PATCH] Testtools should provide distutils integration
  https://bugs.launchpad.net/bugs/693773

For more details, see:
https://code.launchpad.net/~jml/testtools/distutils-integration-693773/+merge/49550

Since a lot of projects use distutils/setuptools for building/packaging/distribution and because testing is a vital part of that workflow, testtools should provide a distutils command class to make it easily integratable into an existing workflow.

The patch attached is a minimal implementation of such a command.

-- 
https://code.launchpad.net/~jml/testtools/distutils-integration-693773/+merge/49550
Your team testtools developers is requested to review the proposed merge of lp:~jml/testtools/distutils-integration-693773 into lp:testtools.
=== modified file 'setup.py'
--- setup.py	2010-12-23 17:38:45 +0000
+++ setup.py	2011-02-13 16:33:57 +0000
@@ -7,7 +7,6 @@
 
 import testtools
 
-
 def get_revno():
     import bzrlib.workingtree
     t = bzrlib.workingtree.WorkingTree.open_containing(__file__)[0]
@@ -62,4 +61,5 @@
       long_description=get_long_description(),
       version=get_version(),
       classifiers=["License :: OSI Approved :: MIT License"],
-      packages=['testtools', 'testtools.testresult', 'testtools.tests'])
+      packages=['testtools', 'testtools.testresult', 'testtools.tests'],
+      cmdclass={'test': testtools.TestCommand})

=== modified file 'testtools/__init__.py'
--- testtools/__init__.py	2011-01-22 17:56:00 +0000
+++ testtools/__init__.py	2011-02-13 16:33:57 +0000
@@ -58,6 +58,9 @@
     ConcurrentTestSuite,
     iterate_tests,
     )
+from testtools.command import (
+    TestCommand
+    )
 
 # same format as sys.version_info: "A tuple containing the five components of
 # the version number: major, minor, micro, releaselevel, and serial. All

=== added file 'testtools/command.py'
--- testtools/command.py	1970-01-01 00:00:00 +0000
+++ testtools/command.py	2011-02-13 16:33:57 +0000
@@ -0,0 +1,60 @@
+# Copyright (c) 2010 Christian Kampka. See LICENSE for details.
+
+"""Extensions to the standard Python unittest library."""
+
+import sys
+
+from distutils.core import Command
+from distutils.errors import DistutilsOptionError
+
+from testtools.run import TestProgram, TestToolsTestRunner
+
+class TestCommand(Command):
+
+    """Command to run unit tests with testtools"""
+
+    description = "run unit tests with testtools"
+
+    user_options = [
+        ('catch', 'c', "Catch ctrl-C and display results so far"),
+        ('buffer', 'b', "Buffer stdout and stderr during tests"),
+        ('failfast', 'f', "Stop on first fail or error"),
+        ('test-module=','m', "Run 'test_suite' in specified module"),
+        ('test-suite=','s', "Test suite to run (e.g. 'some_module.test_suite')")
+    ]
+        
+    def __init__(self, dist):
+        Command.__init__(self, dist)
+        self.runner = TestToolsTestRunner(sys.stdout)
+
+        
+    def initialize_options(self):
+        self.test_suite = None
+        self.test_module = None
+        self.catch = None
+        self.buffer = None
+        self.failfast = None
+    
+    def finalize_options(self):
+        if self.test_suite is None:
+            if self.test_module is None:
+                raise DistutilsOptionError("You must specify a module or a suite to run tests from")
+            else:
+                self.test_suite = self.test_module+".test_suite"
+        elif self.test_module:
+            raise DistutilsOptionError("You may specify a module or a suite, but not both")
+
+        self.test_args = [self.test_suite]
+
+        if self.verbose:
+            self.test_args.insert(0,'--verbose')
+        if self.buffer:
+            self.test_args.insert(0,'--buffer')
+        if self.catch:
+            self.test_args.insert(0,'--catch')
+        if self.failfast:
+            self.test_args.insert(0,'--failfast')
+            
+    def run(self):
+        self.program = TestProgram(argv=self.test_args, testRunner=self.runner, stdout=sys.stdout, exit=False)
+        
\ No newline at end of file

=== added file 'testtools/tests/test_command.py'
--- testtools/tests/test_command.py	1970-01-01 00:00:00 +0000
+++ testtools/tests/test_command.py	2011-02-13 16:33:57 +0000
@@ -0,0 +1,86 @@
+# Copyright (c) 2010 Testtools authors. See LICENSE for details.
+
+"""Tests for the distutils test command logic."""
+
+from testtools.helpers import try_import, try_imports
+fixtures = try_import('fixtures')
+StringIO = try_imports(['StringIO.StringIO', 'io.StringIO'])
+
+import testtools
+import sys
+from testtools import TestCase, run
+from testtools.command import TestCommand
+from distutils.dist import Distribution
+
+if fixtures:
+    class SampleTestFixture(fixtures.Fixture):
+        """Creates testtools.runexample temporarily."""
+
+        def __init__(self):
+            self.package = fixtures.PythonPackage(
+            'runexample', [('__init__.py', """
+from testtools import TestCase
+
+class TestFoo(TestCase):
+    def test_bar(self):
+        pass
+    def test_quux(self):
+        pass
+def test_suite():
+    from unittest import TestLoader
+    return TestLoader().loadTestsFromName(__name__)
+""")])
+
+        def setUp(self):
+            super(SampleTestFixture, self).setUp()
+            self.useFixture(self.package)
+            testtools.__path__.append(self.package.base)
+            self.addCleanup(testtools.__path__.remove, self.package.base)
+            
+class TestCommandTest(TestCase):
+    
+    def test_test_module(self):
+     
+        package = self.useFixture(SampleTestFixture())
+        
+        self.buffer = StringIO()
+         
+        self.dist = Distribution()
+        self.dist.script_name = 'setup.py'
+        self.dist.script_args = ['test']
+        self.dist.cmdclass = {'test': TestCommand}
+        self.dist.command_options = {'test': {'test_module': ('command line', 'testtools.runexample')}}
+        cmd = self.dist.reinitialize_command('test')
+        cmd.runner.stdout = self.buffer
+
+        self.dist.run_command('test')
+        self.assertEqual("""Tests running...
+Ran 2 tests in 0.000s
+
+OK
+""",self.buffer.getvalue())
+
+    def test_test_suite(self):
+     
+        package = self.useFixture(SampleTestFixture())
+        
+        self.buffer = StringIO()
+         
+        self.dist = Distribution()
+        self.dist.script_name = 'setup.py'
+        self.dist.script_args = ['test']
+        self.dist.cmdclass = {'test': TestCommand}
+        self.dist.command_options = {'test': {'test_suite': ('command line', 'testtools.runexample.test_suite')}}
+        cmd = self.dist.reinitialize_command('test')
+        cmd.runner.stdout = self.buffer
+
+        self.dist.run_command('test')
+        self.assertEqual("""Tests running...
+Ran 2 tests in 0.000s
+
+OK
+""",self.buffer.getvalue())      
+
+def test_suite():
+    from unittest import TestLoader
+    return TestLoader().loadTestsFromName(__name__)
\ No newline at end of file


Follow ups