Introduction

When writing production standard code, your program must be tested at many different levels.

For now, let us just talk about the lowest level of tests called Unit Tests. Lowest level doesn't mean Unit Tests are insignificant, it's quite the opposite. These tests make sure that your code is tested at atomic level. Only once all unit tests pass then you can move on to other types of tests in the pyramid.

General guidelines for unit tests :

  1. Each test should focus on an atomic functionality.
  2. A unit test should only test, and never change any data that it is testing.
  3. Units tests should always be independent. What I mean is that, in a certain test file the order of unit tests should be interchangeable.
  4. Use descriptive names for tester functions. This is because other people will need to look over the tests you wrote, modify or add more units tests to them.

Various types of unittests in Python

Unittest

unittest was the most frequently used unit testing module at one time. You define your own classes which subclasses the unittest.TestCase superclass.


In [3]:
import unittest

def cube(x):
    return x ** 3

def square(x):
    return x**2

def add(x, y):
    return x + y

class CalcTest(unittest.TestCase):
    def test_square(self):
        self.assertTrue(square(3) == 9)
        self.assertFalse(square(1) == 2)
        with self.assertRaises(TypeError):
            cube("Lite")
    
    def test_add(self):
        self.assertTrue(add(3, 4) == 9)

    def test_cube(self):
        self.assertEqual(cube(3), 27)

unittest.main(argv=['first-arg-is-ignored'], exit=False, verbosity=2)


test_add (__main__.CalcTest) ... FAIL
test_cube (__main__.CalcTest) ... ok
test_square (__main__.CalcTest) ... ok

======================================================================
FAIL: test_add (__main__.CalcTest)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "<ipython-input-3-de344eaec9d5>", line 20, in test_add
    self.assertTrue(add(3, 4) == 9)
AssertionError: False is not true

----------------------------------------------------------------------
Ran 3 tests in 0.004s

FAILED (failures=1)
Out[3]:
<unittest.main.TestProgram at 0x7fcf7824f358>

You can go the unittest docs if you're interested in knowing more about this module. We won't be focusing on this cause knowing PyTest is important.

Doctest

This module searches for pieces of text that resemble interactive Python sessions in docstrings, and then executes those lines of code to make sure they work. Mostly doctests are simple examples to give an idea of what the function is supposed to do.

The main use of doctests are to improve the documentation of the module by showing some main use cases of the module and its components


In [5]:
import doctest

def concat(*words, sep=" "):
    """Return a sentence from input words
    separated by a separator(default being space)
    
    >>> concat('a','b','c', 'd')
    'a b c d'
    >>> concat('a','1')
    'b 1'
    
    """
    return sep.join(words)

doctest.testmod()


**********************************************************************
File "__main__", line 9, in __main__.concat
Failed example:
    concat('a','1')
Expected:
    'b 1'
Got:
    'a 1'
**********************************************************************
1 items had failures:
   1 of   2 in __main__.concat
***Test Failed*** 1 failures.
Out[5]:
TestResults(failed=1, attempted=2)

PyTest(py.test)

py.test is the no-boilerplate alternative to the unittest module. It has a lot of features and most importantly can be easily extended due to its relatively simple syntax.

Test suites are as simple as writing a module(python file) with couple of test methods.
Let us see some basic examples. To explore pytest better take a look at the pytest docs.

Travis CI

Travis CI is a hosted, distributed continuous integration service used to build and test software projects hosted at GitHub. The best way to understand what it does is to actually create a test repository and then integrate it with Travis CI.

Let's get started !