[Django]-How to get django's unittest TestLoader to find and run my doctests?

1πŸ‘

βœ…

I solved this by creating a new module, my_django_app/tests/test_doctests.py, that looks like:

import doctest
import unittest

# These are my modules that contain doctests:
from util import bitwise
from util import text
from util import urlutil
DOCTEST_MODULES = (
  bitwise,
  text,
  urlutil,
)

# unittest.TestLoader will call this when it finds this module:
def load_tests(*args, **kwargs):
  test_all_doctests = unittest.TestSuite()
  for m in DOCTEST_MODULES:
    test_all_doctests.addTest(doctest.DocTestSuite(m))
  return test_all_doctests

Django uses the builtin unittest TestLoader, which, during test discovery, will call load_tests() on your test module. So we define load_tests which creates a test suite out of all of the doctests.

πŸ‘€Taylor Hughes

2πŸ‘

The automagic of Django unittests discovery looks for a load_tests function in your test_foo module and will run it. So you can use that to add your doctests to the test suite …

import doctest
import module_with_doctests

def load_tests(loader, tests, ignore):
    tests.addTests(doctest.DocTestSuite(module_with_doctests))
    return tests

Also, due to a bug(?) in unittest your load_tests function won’t be run unless your test_foo module also defines a TestCase-derived class like so:

class DoNothingTest(TestCase):
    """Encourage Django unittests to run `load_tests()`."""
    def test_example(self):
        self.assertTrue(True)
πŸ‘€hobs

0πŸ‘

import django.test.runner

testsuite = django.test.runner.DiscoverRunner().build_suite()

but, as best I can tell, basic unittest discover produces the same collection

import unittest

testsuite = unittest.TestLoader().discover('.')

unrelated

I did notice that unittest and django.test appear to use an internal attribute TestCase._testMethodName differently, in unittest, this is the testcase module+class namespace, in django, this appeared to be a random testcase method name, with the module and class being attributes of self.__module__. probably try to avoid needing to poke around in internals anyway though

πŸ‘€ThorSummoner

Leave a comment