How to test coverage properly with Django + Nose How to test coverage properly with Django + Nose django django

How to test coverage properly with Django + Nose


At the moment it's not possible to accurately run coverage alongside with django-nose (because of the way Django 1.7 loads models). So to get the coverage stats, you need to use coverage.py directly from command line, e.g:

$ coverage run --branch --source=app1,app2 ./manage.py test$ coverage report$ coverage html -d coverage-report

You can put coverage.py settings into .coveragerc file in the project root (the same dir as manage.py).

This issue is reported on django-nose GitHub page: https://github.com/django-nose/django-nose/issues/180 so maintainers know about the problem, you can let them know that you're also experiencing this issue.

UPDATE

eliangcs pointed out (django-nose issues on GiHub), that woraround is to modify your manage.py:

import osimport sysif __name__ == "__main__":    # ...    from django.core.management import execute_from_command_line    is_testing = 'test' in sys.argv    if is_testing:        import coverage        cov = coverage.coverage(source=['package1', 'package2'], omit=['*/tests/*'])        cov.erase()        cov.start()    execute_from_command_line(sys.argv)    if is_testing:        cov.stop()        cov.save()        cov.report()

It works, but it's rather "hacky" approach.

UPDATE 2

I recommend for everybody that uses nose to have a look at py.test (http://pytest.org/), which is really good Python testing tool, it integrates well with Django, has a lot of plugins and many more. I was using django-nose, but tried py.test and never looked back.


As the docs say, "use the command line to run your program with coverage":

coverage run --branch --source=notify ./manage.py test


I spent sometime with this problem, and even with the answers given, they were not detailed enough to fully explain what I was experiencing. Here is what works well for me now, as per answer from iyn with a few necessary tweaks. My manage.py looks like this:

#!/usr/bin/env pythonimport osimport sysif __name__ == "__main__":    os.environ.setdefault("DJANGO_SETTINGS_MODULE", "settings")    try:        from django.core.management import execute_from_command_line    except ImportError as exc:        raise ImportError(            "Couldn't import Django. Are you sure it's installed and "            "available on your PYTHONPATH environment variable? Did you "            "forget to activate a virtual environment?"        ) from exc    # See https://stackoverflow.com/questions/24668174/how-to-test-coverage-properly-with-django-nose    is_coverage_testing = 'test' in sys.argv and '--with-coverage' in sys.argv    # Drop dupe with coverage arg    if '--with-coverage' in sys.argv:        sys.argv.remove('--with-coverage')    if is_coverage_testing:        import coverage        cov = coverage.coverage(source=['client_app', 'config_app', 'list_app', 'core_app', 'feed_app',                                        'content_app', 'lib',                                        'job_app', 'license_app', 'search_app', 'weather_app'],                                omit=['*/integration_tests/*'])        cov.erase()        cov.start()    execute_from_command_line(sys.argv)    if is_coverage_testing:        cov.stop()        cov.save()        cov.report()

As can be seen above, I included all my apps for testing and excluded where I keep my integration tests.

My settings.py I dropped using cover package and with-coverage as this is already handled in manage.py now. Here is my settings with some explanations:

TEST_RUNNER = 'django_nose.NoseTestSuiteRunner'# These are global options, trim as needed# See https://stackoverflow.com/questions/24668174/how-to-test-coverage-properly-with-django-noseNOSE_ARGS = [    # '--cover-package=client_app',  # included in manage.py (hack to include all app testing)    # '--cover-package=config_app',    # '--cover-package=content_app',    # '--cover-package=job_app',    # '--cover-package=lib',    # '--cover-package=license_app',    # '--cover-package=list_app',    # '--cover-package=search_app',    # '--cover-package=core_app',    # '--cover-package=weather_app',    # '--cover-package=feed_app',    '--logging-level=INFO',    '--cover-erase',    # '--with-coverage',  # Included in manage.py (hack), do not use here or will create multiple reports    # '--cover-branches',  # Lowers coverage    '--cover-html',  # generate HTML coverage report    '--cover-min-percentage=59',    # '--cover-inclusive',  # can't get coverage results on most files without this... This breaks django tests.]

I run my basic tests like so (with coverage):

./manage.py test --noinput --verbose --with-coverage

And now I can see models.py, admins.py as well as apps.py gets covered.

I run my integration tests like so (without coverage):

./manage.py test integration_tests/itest_*  --noinput

I can also run a specific set of tests like so:

./manage.py test --noinput --verbose client_app/tests.py

You can also modify NOSE_ARGS as you wish or leave it out completely if you intend to use the flags each time on the command line. Cheers!