Search code examples
pythoncode-coveragepython-unittestnose

Detect missing unittests


I am refactoring a legacy Python project, which did not have any unittests.
Assuming a directory structure like this:

C:.
├───scripts
│       schema.sql
├───src
│   │   .coverage
│   │   bar.py
│   │   baz.py
│   │   foo.py
│   │   __init__.py
│   └───utils
│           __init__.py
└───tests
        .coverage
        test_foo.py

foo.py looks like:

import bar
import baz
import requests
import psycopg2
import os
import sys

print(requests.__file__)


def foo():
    return 'foo'


if __name__ == '__main__':
    print(foo())

test_foo.py looks like:

import unittest
import foo


class Test_Foo(unittest.TestCase):
    def test_foo(self):
        result = foo.foo()
        self.assertEqual(result, 'foo')

I've just defined tests for foo.py, running the unittests:

python.exe -m unittest discover -s . && coverage report -m
C:\data\...\venv\lib\site-packages\requests\__init__.py
.
----------------------------------------------------------------------
Ran 1 test in 0.000s

OK
Name                           Stmts   Miss  Cover   Missing
------------------------------------------------------------
C:\data\myProject\src\bar.py       2      1    50%   2
C:\data\myProject\src\foo.py      11      4    64%   6-8, 12, 16
------------------------------------------------------------
TOTAL                             13      5    62%

Using nose, the output shows missing tests for packages within 'site-packages' as well which I dont want to see:

nosetests -w ..\src --cover-inclusive  --cover-tests --with-coverage --cover-erase --cover-html

Name                                    Stmts   Miss  Cover
-----------------------------------------------------------
bar.py                                      2      1    50%
baz.py                                      2      1    50%
certifi\__init__.py                         2      2     0%
...
decimal.py                                 10     10     0%
encodings\idna.py                         180    180     0%
hmac.py                                    60     60     0%
http\client.py                            756    756     0%
http\client.py                            756    756     0%
http\cookiejar.py                        1102   1102     0%
http\cookies.py                           248    248     0%
idna\__init__.py                            4      4     0%
idna\__init__.py                            4      4     0%
idna\core.py                              291    291     0%
idna\core.py                              291    291     0%
idna\idnadata.py                            4      4     0%
idna\idnadata.py                            4      4     0%
idna\intranges.py                          30     30     0%
idna\intranges.py                          30     30     0%
idna\package_data.py                        1      1     0%
idna\package_data.py                        1      1     0%
mimetypes.py                              194    194     0%
numbers.py                                134    134     0%
psycopg2\__init__.py                       22     22     0%
...
src\__init__.py                             0      0   100%
src\bar.py                                  2      1    50%
src\baz.py                                  2      1    50%
src\foo.py                                 11      2    82%
src\utils\__init__.py                       0      0   100%
stringprep.py                              65     65     0%
urllib3\__init__.py                        34     34     0%
...
-----------------------------------------------------------
TOTAL                                   14613  14600     1%
----------------------------------------------------------------------
Ran 0 tests in 0.000s

OK

How do I see a regular unittest/coverage report and additionally files within the working directory which haven't been tested ?


Solution

  • You could use pytest.
    Recreating your directory structure and optionally removing import baz in foo.py:

    import bar                    
    # import baz                  
    import requests               
    import psycopg2               
    import os                     
    import sys                    
                                  
    print(requests.__file__)      
                                  
                                  
    def foo():                    
        return 'foo'              
                                  
                                  
    if __name__ == '__main__':    
        print(foo())  
    
            
    

    Executing pytest:

    pytest --cov-report html:cov_html --cov-report term-missing --cov=src tests/
    

    Output:

    ===== test session starts 
    ... omitted output ...
    collected 1 item
    
    tests\test_foo.py .                                                                                                                                                                              [100%]
    
    ----------- coverage: platform win32, python 3.7.9 -----------
    Name                    Stmts   Miss  Cover   Missing
    -----------------------------------------------------
    src\__init__.py             0      0   100%
    src\bar.py                  2      1    50%   2
    src\baz.py                  2      2     0%   2-3
    src\foo.py                 10      1    90%   16
    src\utils\__init__.py       0      0   100%
    -----------------------------------------------------
    TOTAL                      14      4    71%
    Coverage HTML written to dir cov_html
    

    pytest shows 0% coverage for baz.py