0

I am running tests on a project I've been assigned to. Everything is triggered by calling tox. Default tests run with nose, which adds a coverage report, this is the command that tox calls:

django-admin test -s

and settings file has this configuration for nose:

NOSE_ARGS = [
    '--with-coverage',
    '--cover-erase',
    '--cover-package=app_name',
    '--cover-inclusive'
]

This is the report that's shown while running nose with tox:

Name                                                    Stmts   Miss  Cover
---------------------------------------------------------------------------
app_name/__init__.py                                       0      0   100%
app_name/apps.py                                           3      0   100%
app_name/apps_settings.py                                 12      2    83%
app_name/base.py                                         118     27    77%
app_name/choices.py                                       18      0   100%
app_name/constants.py                                      6      0   100%
app_name/exceptions.py                                    10      0   100%
app_name/helpers/__init__.py                               0      0   100%
app_name/helpers/util.py                                  20     10    50%
app_name/management/__init__.py                            0      0   100%
app_name/migrations/0001_initial.py                        9      0   100%
app_name/migrations/__init__.py                            0      0   100%
app_name/mixins.py                                         6      0   100%
app_name/models.py                                        64      4    94%
app_name/permissions.py                                    7      3    57%
app_name/serializers/__init__.py                           0      0   100%
app_name/serializers/address_serializer.py                 7      0   100%
app_name/serializers/base_response_serializer.py           7      0   100%
app_name/serializers/body_request_user_serializer.py      14      0   100%
app_name/serializers/contact_serializer.py                 4      0   100%
app_name/serializers/file_serializer.py                   11      2    82%
app_name/serializers/iban_serializer.py                    3      0   100%
app_name/serializers/identification_serializer.py         11      2    82%
app_name/serializers/payment_account_serializer.py         3      0   100%
app_name/serializers/transfer_serializer.py               20     10    50%
app_name/services/__init__.py                              0      0   100%
app_name/services/authentication_service.py                7      0   100%
app_name/services/document_service.py                     23      9    61%
app_name/services/user_service.py                         37     21    43%
app_name/services/webhook_service.py                      26      7    73%
app_name/storage_backends.py                              10      0   100%
app_name/views/__init__.py                                 0      0   100%
app_name/views/webhook_view.py                            25      8    68%
---------------------------------------------------------------------------
TOTAL                                                     481    105    78%
----------------------------------------------------------------------
Ran 5 tests in 4.615s

But, if after it I run coverage report this is shown:

Name                                                      Stmts   Miss  Cover
-----------------------------------------------------------------------------
app_name/__init__.py                                         0      0   100%
app_name/apps.py                                             3      0   100%
app_name/apps_settings.py                                   12      2    83%
app_name/base.py                                           118     27    77%
app_name/choices.py                                         18      0   100%
app_name/constants.py                                        6      0   100%
app_name/decorators.py                                      10      7    30%
app_name/exceptions.py                                      10      0   100%
app_name/helpers/__init__.py                                 0      0   100%
app_name/helpers/util.py                                    20     10    50%
app_name/management/__init__.py                              0      0   100%
app_name/management/commands/__init__.py                     0      0   100%
app_name/management/commands/generate_uuid.py                9      4    56%
app_name/migrations/0001_initial.py                          9      0   100%
app_name/migrations/__init__.py                              0      0   100%
app_name/mixins.py                                           6      0   100%
app_name/models.py                                          64      4    94%
app_name/permissions.py                                      7      3    57%
app_name/serializers/__init__.py                             0      0   100%
app_name/serializers/address_serializer.py                   7      0   100%
app_name/serializers/base_response_serializer.py             7      0   100%
app_name/serializers/body_request_token_serializer.py        4      0   100%
app_name/serializers/body_request_user_serializer.py        14      0   100%
app_name/serializers/contact_serializer.py                   4      0   100%
app_name/serializers/document_serializer.py                  7      0   100%
app_name/serializers/file_serializer.py                     11      2    82%
app_name/serializers/files_serializer.py                     4      0   100%
app_name/serializers/iban_serializer.py                      3      0   100%
app_name/serializers/identification_serializer.py           11      2    82%
app_name/serializers/payment_account_serializer.py           3      0   100%
app_name/serializers/transfer_serializer.py                 20     10    50%
app_name/serializers/user_information_serializer.py          7      0   100%
app_name/services/__init__.py                                0      0   100%
app_name/services/account_service.py                        62     45    27%
app_name/services/authentication_service.py                  7      0   100%
app_name/services/document_service.py                       23      9    61%
app_name/services/method_service.py                         23     15    35%
app_name/services/user_service.py                           37     21    43%
app_name/services/webhook_service.py                        26      7    73%
app_name/storage_backends.py                                10      0   100%
app_name/tests/__init__.py                                   0      0   100%
app_name/tests/apps/__init__.py                              0      0   100%
app_name/tests/apps/apps_test.py                             9      0   100%
app_name/tests/helpers/__init__.py                           0      0   100%
app_name/tests/helpers/helpers_test.py                       7      0   100%
app_name/tests/services/__init__.py                          0      0   100%
app_name/tests/services/authentication_service_test.py       8      0   100%
app_name/tests/services/document_service_test.py            13      0   100%
app_name/tests/services/user_service_test.py                13      0   100%
app_name/urls/__init__.py                                    0      0   100%
app_name/urls/webhook_url.py                                 7      2    71%
app_name/views/__init__.py                                   0      0   100%
app_name/views/webhook_view.py                              25      8    68%
-----------------------------------------------------------------------------
TOTAL                                                       664    178    73%

Now, as you can see, certain files were ignored by nose report, but shown by coverage, like app_name/services/account_service.py. And since that file contains feature code it should be shown on report.

The interesting thing here is that, as far as I know, both libraries: nose and coverage are generating their reports from the same report file .coverage

I guess this is a default nose behavior. I'm not very familiar with nose so perhaps anyone can tell me why this difference of behavior happens.

Alvaro Rodriguez Scelza
  • 3,643
  • 2
  • 32
  • 47
  • 1
    The main thing to know about nose is that it has been unmaintained for more than 5 years. You should move to another test runner (pytest). – Ned Batchelder May 08 '21 at 11:02
  • Hi @NedBatchelder thanks for your help. Do you have some link I can show my coworkers in order to prove that? I would like to have good arguments so as to try and convince them to move from nose to django test (which uses unittest if I am correct). Also, would you recommend using django test? – Alvaro Rodriguez Scelza May 09 '21 at 18:38
  • 1
    The nose repo last had a commit more than five years ago: https://github.com/nose-devs/nose/ . The last release was almost six years ago: https://pypi.org/project/nose/#history . The first sentence of the nose docs (https://nose.readthedocs.io/en/latest/) says it's in maintenance mode ("Nose has been in maintenance mode for the past several years...") and that note was added in Nov 2016: https://github.com/nose-devs/nose/commit/0f40fa995384afad77e191636c89eb7d5b8870ca Everywhere you look are clues that this is an old unmaintained tool. – Ned Batchelder May 09 '21 at 22:26

0 Answers0