Python: What's the right way to make modules visible to a TestRunner?
Question: after watching a couple of presentations about django testing, I want to code
my own TestRunner in order to skip django tests, and create better packages
structures for my tests.

The problem is that we've changed the project structure and the test runner
can't find the right path to do the tests discovery. This is how my project
looks like:

    
    
    project/
      -src/
        - project_name/
          - apps/
          - test/ # Not a good name, i know, will change it
             - some_app/
    
               - test_models.py
        - manage.py
        - development.db
    

Now, in order to test `test_models.py` I want to do this:

    
    
    $ cd project/src/
    $ python manage.py test some_app.test_models
    

The problem is that the test runner can't find that package (`some_app`) and
module (`test_models.py`). It changes if I hardcode the name in the test
runner, but i don't like to do it. Here's what I do to make it work.

    
    
    test_labels = ["%s.%s" % ("project_name.test", l)
                               for l in test_labels
                               if not l.startswith("project_name.test")]
    

So, if you do

    
    
    $ python manage.py test some_app.test_models
    

It will be rewritten to:

    
    
    $ python manage.py test project_name.test.some_app.test_models
    

And that works fine.

I tried doing `sys.path.append("(...)/project_name/test)` but doesn't work
neither.

This is the code of my TestRunner:

    
    
    class DiscoveryDjangoTestSuiteRunner(DjangoTestSuiteRunner):
        """A test suite runner that uses unittest2 test discovery.
        It's better than the default django test runner, becouse it
        doesn't run Django tests and let you put your tests in different
        packages, modules and classes.
    
        To test everything in there:
            $ ./manage.py test
    
        To test a single package/module:
    
            $ ./manage.py test package
            $ ./manage.py test package.module
    
        To test a single class:
    
            $ ./manage.py test package.module.ClassName
        """
        def build_suite(self, test_labels, extra_tests=None, **kwargs):
            suite = None
            discovery_root = settings.TEST_DISCOVERY_ROOT
            if test_labels:
                # This is where I append the path
                suite = defaultTestLoader.loadTestsFromNames(test_labels)
                # if single named module has no tests, do discovery within it
                if not suite.countTestCases() and len(test_labels) == 1:
                    suite = None
                    discovery_root = import_module(test_labels[0]).__path__[0]
    
            if suite is None:
                suite = defaultTestLoader.discover(
                    discovery_root,
                    top_level_dir=settings.BASE_PATH,
                    )
    
            if extra_tests:
                for test in extra_tests:
                    suite.addTest(test)
    
            return reorder_suite(suite, (TestCase,))
    


Answer: Before you continue investing more time into your custom `TestRunner`, I would
definitely recommend that you take a look at [`django-
nose`](https://github.com/jbalogh/django-nose).

The custom test runner provided by `django-nose` implements
[`nose`](http://readthedocs.org/docs/nose/en/latest/)'s test runner which is
extremely flexible and provides a lot of options for running your tests. It
seamlessly overrides the default `test` management command and allows you to
configure default test options in your project's `settings` module.

I'm really recommending it for several reasons:

  * The options for the `test` command are fully documented ([take look at the output](https://gist.github.com/2597247))
  * nose provides _a lot_ of approaches for [test discovery](http://readthedocs.org/docs/nose/en/latest/finding_tests.html)
  * Chances are your colleagues are already seasoned nose users
  * You didn't have to write the `TestRunner` class yourself 

