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. ** **
Python 2.7.11
Python
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.
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
The basic usage is as follows.
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.
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
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
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
[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)
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 |
references Below are references and sites.
Recommended Posts