Python standard unittest usage notes

Introduction

Positioning of this memo

This commentary is a brief note of how to use Python's unittest features. The purpose is to explain what Python's unit testing capabilities look like, and to provide a simple example and a template for when you want to do some testing in the future.

It does not deal with how to use doctest.

Also, I think I use nosetests when running many tests, but I don't explain that either.

** Of course, reading a book or official document will give you useful knowledge, and if you use it at work, you should read a proper one instead. For everyone. ** **

Target Python version

Python 2.7.11

Python

What is Python unit test?

A set of modules that implement useful features for testing Python code. It is included in the Python execution environment and should be available when you install Python. It can be used by importing as follows.

import unittest

There seem to be a lot of other test tools. Take a look at the sites on refernces.

Official documentation

For more information on Python unittest features, see the official documentation.

First, it briefly describes what kind of function it has. After that, examples of how to use it are shown so that many people should suppress this usage. From the middle stage onward, there are details of each function and a list of Assert hogehoge methods used for testing.

English version: https://docs.python.org/2.7/library/unittest.html Japanese version: https://docs.python.org/ja/2.7/library/unittest.html#module-unittest

How to use

How to use

The basic usage is as follows.

  1. Import unittest
  2. Create a class TestHOGEHOGE that inherits unittest.TestCase
  3. Describe the test case in TestHOGEHOGE. The test case uses a set of methods named AssertHOGE (). This method compares the match, magnitude relationship, etc.
  4. Run the test with unittest.main (). If the desired result is achieved, the result is success, otherwise failure.

The most basic example

Suppose you have some suitable code. For example, the following method that just adds.

tashizan.py



def tashizan(a, b):
    """ calculate (a + b)
    """
    return a + b

I want to test this. The function that should be fulfilled would be that the addition is being performed correctly (not subtraction, etc.). I will write a module for that.

test_tashizan.py



import unittest
from tashizan import tashizan


class TestTashizan(unittest.TestCase):
    """test class of tashizan.py
    """

    def test_tashizan(self):
        """test method for tashizan
        """
        value1 = 2
        value2 = 6
        expected = 8
        actual = tashizan(value1, value2)
        self.assertEqual(expected, actual)


if __name__ == "__main__":
    unittest.main()

Hitting unittest.main () will run a group of tests. The result of doing this is as follows.

$ python test_tashizan.py
.
----------------------------------------------------------------------
Ran 1 test in 0.000s

OK

When unittest.main () is executed, all the classes that inherit unittest.TestCase in the target script are recognized in the target script, and all the methods with names starting with test are executed as test cases.

Run only specific test methods

If there are multiple tests, execute the above method and they will be executed at once. The result of adding subtraction to the previous one and executing it is as follows

keisan.py


def tashizan(a, b):
    """calculate a+b

    :param a: value 1(int)
    :param b: value 2(inte)
    :return: a + b
    """
    return a + b


def hikizan(a, b):
    """calculate a - b

    :param a:  value 1(int)
    :param b:  value 2(int)
    :return:  a - b
    """
    return a - b

--−−−

test_keisan.py


import unittest
import keisan


class TestKeisan(unittest.TestCase):
    """test class of keisan.py
    """

    def test_tashizan(self):
        """test method for tashizan
        """
        value1 = 2
        value2 = 6
        expected = 8
        actual = keisan.tashizan(value1, value2)
        self.assertEqual(expected, actual)


class TestKeisan2(unittest.TestCase):
    def test_hikizan(self):
        """test method for hikizan
        """
        value1 = 2
        value2 = 12
        expected = -10
        actual = keisan.hikizan(value1, value2)
        self.assertEqual(expected, actual)


if __name__ == "__main__":
    unittest.main()

$ python test_keisan.py -v
test_tashizan (__main__.TestKeisan)
test method for tashizan ... ok
test_hikizan (__main__.TestKeisan2)
test method for hikizan ... ok

----------------------------------------------------------------------
Ran 2 tests in 0.000s

OK

(Arbitrarily separate classes. In the above case, you probably write in one class) However, there are times when you want to run only a specific test class. In that case, use the -m option at run time. An example is shown below. Here, by adding the -v option after unittest, information about the test content is displayed. If you do python -m -v ..., the -v option will be passed to the python interpreter, so a lot of information unrelated to the test will be displayed. (See @ skawagt's comment)

$ python  -m unittest test_keisan.TestKeisan2 -v
.
test_hikizan (test_keisan.TestKeisan2)
test method for hikizan ... ok

----------------------------------------------------------------------
Ran 1 test in 0.000s

OK

Summarize the processing before and after test case execution

Initializing the value can be time-consuming. When you want to check various operations on a specific object, it is troublesome to enter a value for each test case. In that case, there are setUp and tearDown methods that are convenient. SetUp and tearDown will be executed for each test case.

Here's an example of when you have a class of quadratic equations and want to test them.

QuadraticEquation.py


import numpy as np


class QuadraticEquation(object):
    """Quadratic equation class
    """

    def __init__(self):
        self.a = 1.0
        self.b = 2.0
        self.c = 1.0

    def calc_root(self):
        """calculate root

        :return: root1, root2 (root1 < root2)
        """
        x1 = (-1.0 * self.b - np.sqrt(self.b * self.b - 4.0 * self.a * self.c)) / (2.0 * self.a)
        x2 = (-1.0 * self.b + np.sqrt(self.b * self.b - 4.0 * self.a * self.c)) / (2.0 * self.a)
        return x1, x2

    def calc_value(self, x):
        """ calculate polynomial value

        :param x: x
        :return: a * x^2 + b * x + c
        """

        return self.a * np.power(x, 2.0) + self.b * x + self.c

The test case for this is as follows.

test_quadraticEquation.py


import unittest
import QuadraticEquation
from unittest import TestCase


class TestQuadraticEquation(unittest.TestCase):
    def setUp(self):
        print "setup"
        self.eq = QuadraticEquation.QuadraticEquation()

    def test_calc_root(self):
        """ test method of s"""
        expected = (-1.0, -1.0)
        actual = self.eq.calc_root()

        self.assertEqual(expected, actual)
        self.assertEqual((0.0, 0.0), (self.eq.calc_value(actual[0]), self.eq.calc_value(actual[1])))

    def test_calc_value(self):
        """ test method of calc_value() """
        expected = (4.0, 9.0)
        actual = (self.eq.calc_value(1.0), self.eq.calc_value(2.0))

        self.assertEqual(expected, actual)

    def tearDown(self):
        print "tearDown"
        del self.eq


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

When executed with this, you can see that the setUp and tearDown methods are called at the beginning and end of the test case as shown below.

$ python -m unittest test_quadraticEquation
setup
tearDown
.setup
tearDown
.
----------------------------------------------------------------------
Ran 2 tests in 0.000s

OK

Do a group of tests at once

In reality, I think it's the case when you have multiple modules that you bother to explicitly create and test unit tests. In that case, you can't just hit a lot of test modules by hand.

In that case, you can use the discover function of unittest.

$ python -m unittest discover

Given the above two test cases

$ ls
QuadraticEquation.py  keisan.py  test_keisan.py  test_quadraticEquation.py

Using the above discover, it looks like this: All tests were run.

$ python -m unittest discover
....
----------------------------------------------------------------------
Ran 4 tests in 0.000s

OK

Measure coverage

[Unfinished]

You may want to measure test coverage, but this is probably not a feature of unittest. So Use coverage.

$ pip install coverage

You can use this to measure the coverage of a module or create an html file ... But to do a lot You have to write the script yourself.

Since there is nosetests, it would be better to use it (throwing)

Asset method list

Excerpt from the official. Almost Equal is also useful for comparing floats. This is not all, so please refer to the formula.

ASSER method type Check target
assertEqual(a, b) a == b
assertNotEqual(a, b) a != b
assertTrue(x) bool(x) is True
assertFalse(x) bool(x) is False
assertIs(a, b) a is b
assertIsNot(a, b) a is not b
assertIsNone(x) x is None
assertIsNotNone(x) x is not None
assertIn(a, b) a in b
assertNotIn(a, b) a not in b
assertIsInstance(a, b) isinstance(a, b)
assertNotIsInstance(a, b) not isinstance(a, b)
assertAlmostEqual(a, b) round(a-b, 7) == 0
assertNotAlmostEqual(a, b) round(a-b, 7) != 0
assertGreater(a, b) -a > b
assertGreaterEqual(a, b) a >= b
assertLess(a, b) a < b
assertLessEqual(a, b) a <= b
assertRegexpMatches(s, r) r.search(s)
assertNotRegexpMatches(s, r) not r.search(s)
assertDictContainsSubset(a, b) all the key/value pairs in a exist in b

Summary

  1. Import unittest and write a test case in a class that inherits unittest.TestCase ――At this time, with a method like AssetHOGEHOGE
  2. Run the test by hitting unittest.main (). If you want to test various modules at once, use discover

references Below are references and sites.

Recommended Posts

Python standard unittest usage notes
python decorator usage notes
[Python] pytest-mock Usage notes
python * args, ** kwargs Usage notes
Python scraping notes
Python study notes _000
Python learning notes
concurrent.futures Usage notes
Unittest in python
Python beginner notes
Python study notes_006
[Python] Standard input
python C ++ notes
Python study notes _005
Python grammar notes
Python Library notes
python personal notes
python pandas notes
Python study notes_001
python learning notes
Python3.4 installation notes
missingintegers python personal notes
Python package development notes
python unittest assertXXX list
Usage of Python locals ()
Python ipaddress package notes
[Personal notes] Python, Django
Python Pickle format notes
First Python miscellaneous notes
Matlab => Python migration notes
Notes around Python3 assignments
Notes using Python subprocesses
[Python] About standard input
Python try / except notes
Python framework bottle notes
Directory structure when writing tests with Python 3 standard unittest
Python notes using perl-ternary operator
O'Reilly python3 Primer Learning Notes
Python 3.4 or later standard pip
Web scraping notes in python3
[Python3] Standard input [Cheat sheet]
Python notes to forget soon
Python notes using perl-special variables
Python 處 處 regular expression Notes
Python Tkinter notes (for myself)
Convenient diff command usage notes
Python3 standard input (competition pro)
Standard input / summary / python, ruby
Receiving standard input tips @ python
[Python] Notes on data analysis
Transposed matrix in Python standard
Python data analysis learning notes
Notes on installing Python on Mac
Sample usage of Python pickle
Unittest and CI in Python
Basic usage of Python f-string
Get Evernote notes in Python
[Python] Correct usage of join
python standard virtual environment venv
Notes on installing Python on CentOS
Python3 standard input for competitive programming