How to test coverage properly with Django + Nose

后端 未结 5 1516
走了就别回头了
走了就别回头了 2020-12-29 08:54

Currently have a project configured to run coverage via Django\'s manage command like so:

./manage.py test --with-coverage --cover-package=notify --cover-bra         


        
5条回答
  •  予麋鹿
    予麋鹿 (楼主)
    2020-12-29 09:34

    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 python
    import os
    import sys
    
    if __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-nose
    NOSE_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!

提交回复
热议问题