75

I created custom django-admin commands

But, I don't know how to test it in standard django tests

6 Answers 6

133

If you're using some coverage tool it would be good to call it from the code with:

from django.core.management import call_command
from django.test import TestCase

class CommandsTestCase(TestCase):
    def test_mycommand(self):
        " Test my custom command."

        args = []
        opts = {}
        call_command('mycommand', *args, **opts)

        # Some Asserts.

From the official documentation

Management commands can be tested with the call_command() function. The output can be redirected into a StringIO instance

Sign up to request clarification or add additional context in comments.

4 Comments

The above link is broken, access the latest version of mentioned doc here.
My command creates entries in the database, do you know how to use the testdb ?
@SWater Hi, as far as I understand, the TestCase from django.test uses the test database, see here
25

You should make your actual command script the minimum possible, so that it just calls a function elsewhere. The function can then be tested via unit tests or doctests as normal.

2 Comments

Not sure I agree with this. If I could do that, I probably would not make it a Django command. I would just run it as a python program. The reason I make Django commands is to get all the Django infrastructure.
Well, sometimes you can't just run it as a python program because of the import issues.
22

you can see in github.com example see here

from StringIO import StringIO

from django.test import TestCase
from django.core import management

class CommandTests(TestCase):

    def test_command_style(self):
        out = StringIO()
        management.call_command('dance', style='Jive', stdout=out)
        self.assertEquals(out.getvalue(), "I don't feel like dancing Jive.")

1 Comment

mybe you need out.getvalue().strip()
7

To add to what has already been posted here. If your django-admin command passes a file as parameter, you could do something like this:

from django.test import TestCase
from django.core.management import call_command
from io import StringIO
import os


class CommandTestCase(TestCase):
    def test_command_import(self):
        out = StringIO()
        call_command(
            'my_command', os.path.join('path/to/file', 'my_file.txt'),
            stdout=out
        )
        self.assertIn(
        'Expected Value',
            out.getvalue()
        )

This works when your django-command is used in a manner like this:

$ python manage.py my_command my_file.txt

Comments

-1

A simple alternative to parsing stdout is to make your management command exit with an error code if it doesn't run successfully, for example using sys.exit(1).

You can catch this in a test with:

    with self.assertRaises(SystemExit):
        call_command('mycommand')

Comments

-3

I agree with Daniel that the actual command script should do the minimum possible but you can also test it directly in a Django unit test using os.popen4.

From within your unit test you can have a command like

fin, fout = os.popen4('python manage.py yourcommand')
result = fout.read()

You can then analyze the contents of result to test whether your Django command was successful.

1 Comment

don't use subprocesses for this kind of testing, and certainly don't use os.popen4, if you really wanted to do that you'd use the subprocess package.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.