[pypy-svn] rev 2459 - pypy/trunk/src/pypy/tool

sschwarzer at codespeak.net sschwarzer at codespeak.net
Wed Dec 17 18:49:45 CET 2003


Author: sschwarzer
Date: Wed Dec 17 18:49:45 2003
New Revision: 2459

Added:
   pypy/trunk/src/pypy/tool/newtest.py
Log:
Start of a new unit testing framework (hopefully sufficiently flexible
but not too complicated). Much is still missing, though.


Added: pypy/trunk/src/pypy/tool/newtest.py
==============================================================================
--- (empty file)
+++ pypy/trunk/src/pypy/tool/newtest.py	Wed Dec 17 18:49:45 2003
@@ -0,0 +1,133 @@
+import autopath
+import imp
+import os
+import sys
+import unittest
+import vpath
+
+
+# named constants for test result status values
+SUCCESS = 'success'
+ERROR = 'error'
+FAILURE = 'failure'
+IGNORED = 'ignored'
+SKIPPED = 'skipped'
+
+class TestResult:
+    """Represent the result of a run of a test item."""
+    def __init__(self, item, status=None, fullname=None, traceback=None):
+        # one of SUCCESS, ERROR, FAILURE, IGNORED, SKIPPED
+        self.status = None
+        # name of the test method (without class or module name)
+        self.methodname = None
+        # full method name (with module path and class name)
+        self.fullname = None
+        # traceback object if applicable, else None
+        self.traceback = None
+        # formatted traceback (a string)
+        self.formatted_traceback = None
+
+
+class TestItem:
+    """Represent a single test method from a TestCase class."""
+    def __init__(self, testmethod):
+        #TODO implement the code to initialze these attributes
+        self.module = None
+        self.file = None
+        self.lineno = None
+        self.source = None
+        self._method = testmethod
+        self._class = testmethod.__class__
+
+    def run(self):
+        """Run this TestItem and return a corresponding TestResult object."""
+        #XXX at a later time, this method may accept an object space
+        #  as argument
+
+    def __str__(self):
+        return "TestItem from method %s" % self._method
+
+    __repr__ = __str__
+
+
+class TestSuite:
+    """Represent a collection of test items."""
+    def __init__(self):
+        self.items = []
+
+    def _items_from_module(self, module):
+        """Return a list of TestItems read from the given module."""
+        items = []
+        # scan the module for classes derived from unittest.TestCase
+        for obj in vars(module).values():
+            try:
+                is_testclass = issubclass(obj, unittest.TestCase)
+            except TypeError:
+                # not a class at all; ignore it
+                continue
+            if not is_testclass:
+                continue
+            # scan class for test methods
+            for obj in vars(obj).values():
+                if hasattr(obj, 'func_code') and \
+                  obj.__name__.startswith("test"):
+                    items.append(TestItem(obj))
+        return items
+
+    def _module_from_modpath(self, modpath):
+        """
+        Return a module object derived from the module path
+        (e. g. "pypy.module.builtin.test.test_minmax").
+        """
+        # This __import__ call is only used to ensure that the module
+        # is present in sys.modules. Unfortunately, the module returned
+        # from the __import__ function doesn't correspond to the last
+        # component of the module path but the first. In the example
+        # listed in the docstring we thus would get the pypy module,
+        # not the test_minmax module.
+        __import__(modpath)
+        return sys.modules[modpath]
+
+    def initfromdir(self, dirname, filterfunc=None, recursive=True,
+                    loader=None):
+        """
+        Init this suite by reading the directory denoted by dirname,
+        then find all test modules in it. Test modules are files that
+        comply with the shell pattern shell_pattern "test_*.py".
+
+        filterfunc is a callable that can be used to filter the test
+        modules by module path. By default, all test modules are used.
+
+        If recursive is true, which is the default, find all test modules
+        by scanning the start directory recursively. The argument loader
+        may be set to a test loader class to use. By default, the
+        TestLoader class from the unittest module is used.
+        """
+        dirname = vpath.getlocal(dirname)
+        if loader is None:
+            loader = unittest.TestLoader()
+
+        def testfilefilter(path):
+            return path.isfile() and path.fnmatch('test_*.py')
+        def recfilter(path):
+            return recursive and vpath.nodotfile(path)
+
+        for testfn in dirname.visit(testfilefilter, recfilter):
+            # strip the leading pypy directory and the .py suffix
+            modpath = str(testfn)[len(autopath.pypydir)+1:-3]
+            modpath = 'pypy.' + modpath.replace(os.sep, '.')
+            if (filterfunc is None) or filterfunc(modpath):
+                try:
+                    module = self._module_from_modpath(modpath)
+                    items = self._items_from_module(module)
+                except:
+                    print "skipping testfile (failed loading it)", modpath
+                else:
+                    self.items.extend(items)
+
+
+if __name__ == '__main__':
+    ts = TestSuite()
+    ts.initfromdir(".")
+    print ts.items
+


More information about the Pypy-commit mailing list