Rev 2467: Update TestLoader with functionality to auto-find tests to run. in http://bzr.arbash-meinel.com/branches/bzr/0.17-dev/test_autoloader

John Arbash Meinel john at arbash-meinel.com
Fri Apr 27 21:31:33 BST 2007


At http://bzr.arbash-meinel.com/branches/bzr/0.17-dev/test_autoloader

------------------------------------------------------------
revno: 2467
revision-id: john at arbash-meinel.com-20070427203112-y3n41qkr3y9nlr20
parent: pqm at pqm.ubuntu.com-20070426211103-h84prqh7a4ad3ez2
committer: John Arbash Meinel <john at arbash-meinel.com>
branch nick: test_autoloader
timestamp: Fri 2007-04-27 15:31:12 -0500
message:
  Update TestLoader with functionality to auto-find tests to run.
added:
  bzrlib/tests/test_test_util.py test_test_util.py-20070427203042-9m1ldokoqp9hsdwg-1
modified:
  bzrlib/tests/TestUtil.py       TestUtil.py-20050824080200-5f70140a2d938694
  bzrlib/tests/__init__.py       selftest.py-20050531073622-8d0e3c8845c97a64
-------------- next part --------------
=== added file 'bzrlib/tests/test_test_util.py'
--- a/bzrlib/tests/test_test_util.py	1970-01-01 00:00:00 +0000
+++ b/bzrlib/tests/test_test_util.py	2007-04-27 20:31:12 +0000
@@ -0,0 +1,141 @@
+# Copyright (C) 2007 Canonical Ltd
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+"""Test the TestUtil functions and classes.
+
+This tests things like the ability to automatically find test cases.
+"""
+
+import os
+import sys
+
+from bzrlib import tests
+
+
+class TestFindTestFiles(tests.TestCaseInTempDir):
+    """Test that we can find appropriate test files."""
+
+    def assertFindTestFiles(self, files, packages, path):
+        self.assertEqual((files, packages),
+                         tests.TestLoader.find_test_files(path))
+
+    def test_none(self):
+        self.assertFindTestFiles([], [], '.')
+
+    def test_one(self):
+        self.build_tree(['test_foo.py'])
+        self.assertFindTestFiles(['test_foo.py'], [], '.')
+
+    def test_non_package_dir(self):
+        """Only consider it a package if there is an __init__.py"""
+        self.build_tree(['bar/', 'bar/foo', 'bar/baz.py'])
+        self.assertFindTestFiles([], [], '.')
+
+    def test_package(self):
+        self.build_tree(['bar/', 'bar/__init__.py'])
+        self.assertFindTestFiles([], ['bar'], '.')
+
+    def test_subdir(self):
+        self.build_tree(['bar/', 'bar/test_baz.py', 'bar/foo/',
+                         'bar/foo/__init__.py'
+                        ])
+        self.assertFindTestFiles(['test_baz.py'], ['foo'], 'bar')
+
+
+class TestRecursiveLoadTests(tests.TestCaseInTempDir):
+
+    def assertRecursiveLoadTests(self, expected_tests, path):
+        """Assert that recursiveLoadTests works.
+
+        :param expected_tests: A list of test ids that should be loaded.
+        :param path: The path to test files. It is assumed this is a single
+            directory name, so that the python name and the filesystem
+            name are identical.
+        """
+        # Make sure it isn't loaded already.
+        self.assertFalse(path in sys.modules)
+        cwd = os.getcwd()
+        sys.path.insert(0, cwd)
+        module_keys = set(sys.modules.keys())
+        try:
+            loader = tests.TestLoader()
+            suite = loader.recursiveLoadTests(path, path)
+            self.assertIsInstance(suite, tests.TestSuite)
+            self.assertEqual(expected_tests,
+                             [t.id() for t in tests.iter_suite_tests(suite)])
+        finally:
+            sys.path.remove(cwd)
+            new_keys = set(sys.modules.keys())
+            for mod in new_keys - module_keys:
+                del sys.modules[mod]
+
+    def test_find_none(self):
+        self.build_tree(['test1/'])
+        self.assertRecursiveLoadTests([], 'test1')
+
+    def test_find_file(self):
+        self.build_tree(['loader_test/'])
+        self.build_tree_contents([
+            ('loader_test/__init__.py', ''),
+            ('loader_test/test_foo.py',
+               'import unittest\n'
+               'class TestFoo(unittest.TestCase):\n'
+               '  def test_one(self):\n'
+               '    pass\n'
+            ),
+            ])
+        self.assertRecursiveLoadTests(
+            ['loader_test.test_foo.TestFoo.test_one'],
+             'loader_test')
+
+    def test_find_package(self):
+        self.build_tree(['loader_test/', 'loader_test/package/'])
+        self.build_tree_contents([
+            ('loader_test/__init__.py', ''),
+            ('loader_test/package/__init__.py',
+               'import unittest\n'
+               'class TestFoo(unittest.TestCase):\n'
+               '  def test_one(self):\n'
+               '    pass\n'
+               'class TestBar(unittest.TestCase):\n'
+               '  def test_two(self):\n'
+               '    pass\n'
+               '\n'
+               'def test_suite():\n'
+               '  # return TestFoo, but not TestBar\n'
+               '  loader = unittest.TestLoader()\n'
+               '  return loader.loadTestsFromTestCase(TestFoo)\n'
+            ),
+            ])
+        self.assertRecursiveLoadTests(
+            ['loader_test.package.TestFoo.test_one'],
+             'loader_test')
+
+    def test_ignore_no_test_suite(self):
+        self.build_tree(['loader_test/', 'loader_test/package/'])
+        self.build_tree_contents([
+            ('loader_test/__init__.py', ''),
+            ('loader_test/package/__init__.py',
+               'import unittest\n'
+               'class TestFoo(unittest.TestCase):\n'
+               '  def test_one(self):\n'
+               '    pass\n'
+               'class TestBar(unittest.TestCase):\n'
+               '  def test_two(self):\n'
+               '    pass\n'
+            ),
+            ])
+        self.assertRecursiveLoadTests([], 'loader_test')

=== modified file 'bzrlib/tests/TestUtil.py'
--- a/bzrlib/tests/TestUtil.py	2007-04-23 03:41:48 +0000
+++ b/bzrlib/tests/TestUtil.py	2007-04-27 20:31:12 +0000
@@ -16,8 +16,9 @@
 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 #
 
+import logging
+import os
 import sys
-import logging
 import unittest
 
 # Mark this python module as being part of the implementation
@@ -90,6 +91,59 @@
             result.addTests(self.loadTestsFromName(name))
         return result
 
+    @staticmethod
+    def find_test_files(base):
+        """Find test files for all files underneath a given directory.
+
+        :param base: A base directory to look for files and subdirs.
+        :return: ([test_files], [packages]) A list of test files and python
+            packages (dirs with __init__.py) that should contain tests.
+        """
+        names = []
+        # Packages are assumed to have their own 'test_suite' function
+        packages = []
+        for name in os.listdir(base):
+            path = os.path.join(base, name)
+            if os.path.isdir(path):
+                init_path = os.path.join(path, '__init__.py')
+                if os.path.isfile(init_path):
+                    packages.append(name)
+            else:
+                if name.startswith('test') and name.endswith('.py'):
+                    names.append(name)
+        return names, packages
+
+    def recursiveLoadTests(self, base, python_base):
+        """Load all test cases that are underneath base.
+
+        Any test_*.py files in the base directory will be loaded directly. For
+        python packages, they will be loaded and package.test_suite() will be
+        run to get a TestSuite that should be run.
+
+        :param base: The base directory to start looking.
+        :param python_base: The python name matching the base directory.
+        :return: a TestSuite() with all the tests loaded.
+
+        Example:
+            loader = TestLoader()
+            cur_dir = os.path.basename(__file__)
+            loader.recursiveLoadTests(cur_dir, __name__)
+        """
+        names, packages = self.find_test_files(base)
+        modules = []
+        for name in names:
+            assert name.endswith('.py')
+            full_python_name = python_base + '.' + name[:-3]
+            modules.append(full_python_name)
+        suite = self.loadTestsFromNames(modules)
+        for package in packages:
+            pkg_name = python_base + '.' + package
+            pkg = __import__(pkg_name, {}, {}, ['test_suite'])
+            test_suite = getattr(pkg, 'test_suite', None)
+            if test_suite is not None:
+                suite.addTests(test_suite())
+        return suite
+
 
 def _load_module_by_name(mod_name):
     parts = mod_name.split('.')

=== modified file 'bzrlib/tests/__init__.py'
--- a/bzrlib/tests/__init__.py	2007-04-26 09:07:38 +0000
+++ b/bzrlib/tests/__init__.py	2007-04-27 20:31:12 +0000
@@ -2349,6 +2349,7 @@
                    'bzrlib.tests.test_subsume',
                    'bzrlib.tests.test_symbol_versioning',
                    'bzrlib.tests.test_tag',
+                   'bzrlib.tests.test_test_util',
                    'bzrlib.tests.test_testament',
                    'bzrlib.tests.test_textfile',
                    'bzrlib.tests.test_textmerge',



More information about the bazaar-commits mailing list