Django manage.py : Is it possible to pass command line argument (for unit testing)

user4150760 picture user4150760 · Jan 30, 2015 · Viewed 8.8k times · Source

Is it possible to pass command line arguments to Django's manage.py script, specifically for unit tests? i.e. if I do something like

manage.py test myapp -a do_this

Can I receive the value do_this in the setUp function of unit test?

P.S. @Martin asked the justification for using command line args in tests:

  • Some extensive tests take a lot of time and don't need to be run before every commit. I want to make them optional.

  • Occasional debug messages printed by my test cases should be optional

  • Sometimes I just want the tests to go crazy and try a lot more permutations of data.

All the above would be quite convenient with command line options. Once in a while testing can be a lot more extensive or verbose, otherwise it'll be quick.

Answer

clwainwright picture clwainwright · May 9, 2017

I just ran into this problem myself, and I wanted to avoid setting environmental variables on the command line. Environmental variables certainly work, but it's difficult to keep track of which variables have an effect and there's no error message to let you know if you've mistyped one of them.

To get around this I've used argparse to extract extra parameters to the command-line argument. For example, my manage.py file now looks something like this:

#!/usr/bin/env python
import os
import sys
import argparse


if __name__ == "__main__":
    os.environ.setdefault("DJANGO_SETTINGS_MODULE", "project.settings")

    argv = sys.argv
    cmd = argv[1] if len(argv) > 1 else None
    if cmd in ['test']:  # limit the extra arguments to certain commands
        parser = argparse.ArgumentParser(add_help=False)
        parser.add_argument('--foo', default='bar')
        args, argv = parser.parse_known_args(argv)
        # We can save the argument as an environmental variable, in
        # which case it's to retrieve from within `project.settings`,
        os.environ['FOO'] = args.foo
        # or we can save the variable to settings directly if it
        # won't otherwise be overridden.
        from django.conf import settings
        settings.foo = args.foo

    from django.core.management import execute_from_command_line

    # parse_known_args strips the extra arguments from argv,
    # so we can safely pass it to Django.
    execute_from_command_line(argv)

argparse is a really nice library with lots of features. There's a good tutorial on it in the Python docs.