view MoinMoin/_tests/ @ 83:3bf0b6c09275

Updated CHANGES. imported from: moin--main--1.5--patch-85
author Alexander Schremmer <>
date Thu, 06 Oct 2005 16:43:46 +0000
parents df348d27f1fc
children 0c25ccdc8f37
line wrap: on
line source

# -*- coding: iso-8859-1 -*-
MoinMoin Testing Framework

All test modules must be named test_modulename to be included in the
test suit. If you are testing a package, name the test module

Each test_ module may contain test case classes sub classed from
unittest.TestCase or subclass of it. Previous versions required TestCase
suffix, but now its only a convention.

Each test case class may contain multiply test methods, that must start
with 'test'. Those methods will be run by the test suites.

Test that need the current request, for example to create a page
instance, can refer to self.request. It is injected into all test case
classes by the framework.

Tests that require certain configuration, like section_numbers = 1, must
use a TestConfig to create the required configuration before the
test. Deleting the TestConfig instance will restore the previous

See for an example, and use it to create new tests.

Typical Usage

Running all test in this package::

    from MoinMoin._tests import run

Running only few modules::

    run(request, names=['test_this', 'test_that'])

@copyright: 2002-2004 by Jürgen Hermann <>
@license: GNU GPL, see COPYING for details.

from unittest import TestLoader, TextTestRunner

class TestSkipped(Exception):
    """ Raised when a tests is skipped """

TestSkiped = TestSkipped # ensure a stable interface

class TestConfig:
    """ Custom configuration for unit tests
    Some test assume specific configuration, and will fail if the wiki admin
    will change the configuration. For example, DateTime macro test assume 
    the default datetime_fmt.
    When you set custom values in a TestConfig, the previous values are saved,
    and when the TestConfig is deleted, they are restored automatically.
    Typical Usage
        from MoinMoin._tests import TestConfig
        class SomeTestCase(unittest.TestCase):
            def setUp(self):
                self.config = TestConfig(self.request,
                                         defaults=key_list, key=value,...)
            def tearDown(self):
                del self.config
            def testSomething(self):
                # test that needs those defaults and custom values
    def __init__(self, request, defaults=(), **custom):
        """ Create temporary configuration for a test 

        @param request: current request
        @param defaults: list of keys that should use the default value
        @param **custom: other keys using non default values, or new keys
               that request.cfg does not have already
        self.request = request
        self.old = {}  # Old config values = []  # New added attributes
    def setDefaults(self, defaults=()):
        """ Set default values for keys in defaults list
        Non existing default will raise an AttributeError.
        from MoinMoin.multiconfig import DefaultConfig
        for key in defaults:
            self._setattr(key, getattr(DefaultConfig, key))
    def setCustom(self, **custom):
        """ Set custom values """
        for key, value in custom.items():
            self._setattr(key, value)
    def _setattr(self, key, value):
        """ Set a new value for key saving new added keys """
        if hasattr(self.request.cfg, key):
            self.old[key] = getattr(self.request.cfg, key)
        setattr(self.request.cfg, key, value)        
    def __del__(self):
        """ Restore previous request.cfg 
        Set old keys to old values and delete new keys.
        for key, value in self.old.items():
            setattr(self.request.cfg, key, value)
        for key in
            delattr(self.request.cfg, key)

class MoinTestLoader(TestLoader):
    """ Customized test loader that support long running process

    To enable testing long running process, we inject the current
    request into each test case class. Later, each test can refer to
    request as self.request.
    def __init__(self, request):
        self.request = request

    def loadTestsFromTestCase(self, testCaseClass):
        testCaseClass.request = self.request
        return TestLoader.loadTestsFromTestCase(self, testCaseClass)        
    def loadTestsFromModuleNames(self, names):
        """ Load tests from qualified module names, eg. a.b.c
        loadTestsFromNames is broken, hiding ImportErrros in test
        modules. This method is less flexsible but works correctly.
        names = ['%s.%s' % (__name__, name) for name in names]
        suites = []
        for name in names:
            module = __import__(name, globals(), {}, ['dummy'])
        return self.suiteClass(suites)

def makeSuite(request, names=None):
    """ Create test suites from modules in names

    @param request: current request
    @param names: module names to get tests from. If the list is empty,
        all test modules in the _tests package are used.
    @rtype: C{unittest.TestSuite}
    @return: test suite with all test cases in names
    if not names:
        from MoinMoin.util.pysupport import getPackageModules
        names = getPackageModules(__file__)
        names = [name for name in names if name.startswith('test_')]
        caseInsensitiveCompare = lambda a, b: cmp(a.lower(), b.lower())
    return MoinTestLoader(request).loadTestsFromModuleNames(names)

def run(request=None, names=None):
    """ Run test suit

    @param request: current request
    @param names: list fully qualified module names to test,
        e.g MoinMoin._tests.test_error
    if request is None:
        from MoinMoin.request import RequestCLI
        from MoinMoin.user import User
        request = RequestCLI()   
        request.form = request.args = request.setup_args()
        request.user = User(request)
    suite = makeSuite(request, names)
    TextTestRunner(stream=request, verbosity=2).run(suite)