django-nose icon indicating copy to clipboard operation
django-nose copied to clipboard

Django 1.7 model loading screws up test coverage for models

Open diwu1989 opened this issue 10 years ago • 14 comments

Models are imported by the app configuration process running ./manage.py test --with-coverage will report incorrect model coverage information because the models are all imported before the test command is executed

any way to fix this somehow?

diwu1989 avatar Dec 21 '14 10:12 diwu1989

I've been trying to figure this out for the past couple days. My first guess would be that the system check module is interfering with this, but unfortunately setting DEBUG to False did not change anything. It appears you can do something like this, however:

$ coverage run ./manage.py test
$ coverage report
$ coverage html -d cover

to get things working with regular coverage. Unfortunately, this will require more manual setup, but at least it's possible to get things working this way. Right now, I don't think there's an easy fix to making coverage work inside of django-nose. :(

If you want to set things up this way, you'll probably want to make a .coveragerc file that, minimally, specifies source = . and an omit line for wsgi.py.

jchv avatar Dec 21 '14 22:12 jchv

Yes I figured out the more manual way of doing coverage worked as before, it's just sad to see that django nose's coverage feature is so broken in 1.7

diwu1989 avatar Dec 26 '14 23:12 diwu1989

Still doesn't work with Django 1.8, need to run coverage manually. Is there a way to solve this?

this answer from coverage.py FAQ may be related (http://nedbatchelder.com/code/coverage/faq.html):

Q: Why do the bodies of functions (or classes) show as executed, but the def lines do not?

This happens because coverage is started after the functions are defined. The definition lines are executed without coverage measurement, then coverage is started, then the function is called. This means the body is measured, but the definition of the function itself is not.

To fix this, start coverage earlier. If you use the command line to run your program with coverage, then your entire program will be monitored. If you are using the API, you need to call coverage.start() before importing the modules that define your functions.

(emphasis mine)

iyn avatar Apr 15 '15 12:04 iyn

One way to work around it is to modify manage.py to call coverage.start() manually:

import os
import sys

if __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()

eliangcs avatar Apr 15 '15 12:04 eliangcs

@eliangcs thanks for the workaround. :+1: I knew that it's possible to modify manage.py, although I don't consider it the "Django way", it would be better if this worked out of the box, not sure if that's possible though.

iyn avatar Apr 15 '15 22:04 iyn

If there is a way to initialize and start nose coverage in AppConfig.__init__ method, the coverage would be fine, if 'django-nose' would be first app in INSTALLED_APPS list.

That's how I fixed the coverage issue for django-jenkins - https://github.com/kmmbvnr/django-jenkins/blob/master/django_jenkins/apps.py

kmmbvnr avatar Apr 29 '15 07:04 kmmbvnr

I'm not sure if there is a way to fix this purely in django-nose, although the AppConfig.__init__ solution sounds the closest. Does someone want to submit a doc PR with the three solutions mentioned?

jwhitlock avatar Jul 02 '15 22:07 jwhitlock

is there a solution in progress?

AkFede avatar Sep 29 '15 19:09 AkFede

No, I don't believe there is a solution that will work for everyone. I've found @johnwchadwick's solution to be the most reliable, and I'm using that on my own projects.

jwhitlock avatar Oct 01 '15 14:10 jwhitlock

Any progress on a solution for this?

robguttman avatar Oct 29 '15 22:10 robguttman

No, I don't believe there is a solution that will work for everyone. I've found @johnwchadwick's solution to be the most reliable, and I'm using that on my own projects.

jwhitlock avatar Oct 30 '15 15:10 jwhitlock

Deja vu! We use a number of nose plugins including for coverage (e.g., nosexcover for use with jenkins). So I would rather engage that existing nose coverage apparatus than try to repeat it all in a different stack. I tried messing around with the AppConfig.__init__ idea but it wasn't clear how to engage and start the same nose coverage worker that would get used downstream. Sigh - it's looking like I need to retool ..

robguttman avatar Oct 30 '15 16:10 robguttman

In case someone is using buildout+djangorecipe: I just integrated @eliangcs 's solution (https://github.com/django-nose/django-nose/issues/180#issuecomment-93371418) into djangorecipe. Works like a charm.

http://reinout.vanrees.org/weblog/2016/06/30/djangorecipe-test-coverage.html

reinout avatar Jun 30 '16 11:06 reinout

@eliangcs Solution worked great...thanks for that!!

lfritts avatar Sep 19 '16 22:09 lfritts