Unit test and code coverage in python

The solution is an integrated UnitTest + CodeCoverage that will yeld user friendy code coverage report. This is a frequenctly used solution for determining the code coverage used on a Python project.

KEYWORDS

  • Python 2.x
  • Unit test
  • Code coverage

CODE COVERAGE is often requested on projects that needs to follow certain quality measurements.
It is a measurement tool to determine how much of the written code can be covered by certain test scenarios. It's a way also to detect bugs, test the code and to verify all code branches and scenarios.
The code coverage is achieved with unit tests, so all the test scenarios will be reached. Best way to develop unit tests is with a unit test framework that will povide all necessary means to develop the tests so you can only focus on test scenarios and not on the "administrative" part.

A UNIT TEST framework can offer a integrated process to setup-run-destroy the tests. It needs to support automation of test execution, grouping tests in testsuites or test collections and it also needs a reporting mechanism easy to use and understand.

For Unit tests I used unittest library, it's part of the Python standard library group. For coverage tests I used Coverage.py. You can install coverage by running "pip install coverage"

STEP 1. "Hello world" run.

For a simple test run I created the following method to test:
Functions/MathFunctions.py
def absolut(a, b):
retVal = 0
if a > b:
retVal = a-b
else:
retVal = b-a
return retVal

The unittest code for it: Main.py
import unittest
import sys
sys.path.append("Functions")
import MathFunctions
class TestMathMethods(unittest.TestCase):
def test_abs(self):
a = 1
b = 2
self.assertEqual(MathFunctions.absolut(a, b), 1)
if __name__ == '__main__':
unittest.main()

Now to generate the coverage report run in a cmd line:
coverage run Main.py
coverage html

This will create a folder called "htmlcov" where the test is. The index.html is the main file of the report. For this test it looks like this:

Free HTML5 Template by FreeHTML5.co

Coverage is 83% only the a>b branch is not covered.

STEP 2. Using SetUp and TearDown.

The useful part of the framework, besides what is done in the Hello World example refers to having a SETUP/TEAR-DOWN functionality.

So, I added a Logger class:

Functions/Log.py
class Logger:
f = None
WARN_LEVEL = -1

def __init__(self):
self.f = open('logs.txt', 'w')
self.WARN_LEVEL = 0

def write(self, warnLevel, text):
if self.WARN_LEVEL <= warnLevel:
self.f.write(text)

def setWarnLevel(self, lvl):
self.WARN_LEVEL = lvl

def closeFile(self):
self.f.close()

For it I added a unit test functionality:

class TestLogMethods(unittest.TestCase):
log = None

def setUp(self):
self.log = Log.Logger()
self.log.setWarnLevel(1)

def tearDown(self):
self.log.closeFile()

def test_logFile(self):
self.log.write(1, "test")

Here the utility of having some setup/teardown method that executes automatically makes sense.

The methods are overwriteen, so they are virtual in the base class(TestCase class) and they are executed in the order:

  • setUp
  • all methods that starts with test
  • tearDown
  • The output should look like this:

    ..html

    STEP 3. Gourping in test suites.

    A way to group everythoing in test suites for a better grasp of what's running and skiped tests we can use: unittest.main(defaultTest='suite') a param wich is set to all in default mode. I created this file that will describe the test suites.


    alltests.py
    import unittest
    import sys

    sys.path.append('Functions')

    def suite():
    modules_to_test = ('Log', )
    alltests = unittest.TestSuite()
    for module in map(__import__, modules_to_test):
    alltests.addTest(unittest.findTestCases(module))
    return alltests

    if __name__ == '__main__':
    unittest.main(defaultTest='suite')

    Now every test suite can be managed from var modules_to_test

    STEP 4. Running everything with a click.

    I created a .bat file runall.bat containing:
    coverage run alltests.py
    coverage html

    Get Started

    If you need some guidance in engineering field or you're seeking for some help don't hesitate to write me.

    Let's work together