1. doctest
# 文件外命令测试
# file name: foo.py
"""
My square function.
Usage:
>>> a = my_square(4)
>>> b = my_square(3)
>>> a + b
25
"""
def my_square(num):
return num * num
> python3 -m doctest foo.py # 不看详情
> python3 -m doctest -v foo.py # 看详情
# 文件内命令测试
# file-name: foo.py
"""
example usage:
>>> a, b = 2, 3
>>> a+b
5
"""
if __name__ == "__main__":
import doctest
doctest.testmod()
> python3 foo.py -v # 或者ide中run
2. unittest
import unittest
class TestStringMethods(unittest.TestCase):
def test_upper(self):
self.assertEqual('foo'.upper(), 'FOO')
def test_isupper(self):
self.assertTrue('FOO'.isupper())
self.assertFalse('Foo'.isupper())
def test_split(self):
s = 'hello world'
self.assertEqual(s.split(), ['hello', 'world'])
# check that s.split fails when the separator is not a string
with self.assertRaises(TypeError):
s.split(2)
if __name__ == '__main__':
unittest.main()
使用unittest进行测试,如果是需要实现上百个测试用例,把它们全部写在一个test.py文件中,文件会越来越臃肿,后期维护页麻烦。此时可以将这些用例按照测试功能进行拆分,分散到不同的测试文件中。
Python+Unittest - discover()构建不同目录下的用例
discover(start_dir,pattern='test*.py',top_level_dir=None)
找到指定目录下所有测试模块,并可递归查到子目录下的测试模块,只有匹配到文件名才能被加载。如果启动的不是顶层目录,那么顶层目录必须单独指定。
- start_dir:要测试的模块名或测试用例目录
- pattern=‘test*.py’:表示用例文件名的匹配原则。此处匹配文件名以“test”开头的“.py”类型的文件,幸好“*”表示任意多个字符
- top_level_dir=None:测试模块的顶层目录,如果没有顶层目录,默认为None
3. PyTest
pip install pytest
使用方法 pytest test_mymod_1.py
依赖assert
函数
import mymath
def test_math():
assert mymath.add(2, 2) == 4
def test_more_math():
assert mymath.add(3, 3) == 6
import pytest
@pytest.fixture
def input_value():
input = 39
return input
def test_divisible_by_3(input_value):
assert input_value % 3 == 0
def test_divisible_by_6(input_value):
assert input_value % 6 == 0
@pytest.mark.parametrize("num, output",[(1,11),(2,22),(3,35),(4,44)])
def test_multiplication_11(num, output):
assert 11*num == output
pytest -k test_multiplication_11.py -v
test_multiplication.py::test_multiplication_11[1-11] PASSED
test_multiplication.py::test_multiplication_11[2-22] PASSED
test_multiplication.py::test_multiplication_11[3-35] FAILED
test_multiplication.py::test_multiplication_11[4-44] PASSED
============================================== FAILURES
==============================================
_________________ test_multiplication_11[3-35] __________________
num = 3, output = 35
@pytest.mark.parametrize("num, output",[(1,11),(2,22),(3,35),(4,44)])
def test_multiplication_11(num, output):
> assert 11*num == output
E assert (11 * 3) == 35
test_multiplication.py:5: AssertionError
============================== 1 failed, 3 passed, 8 deselected in 0.08 seconds
==============================
pytest.fixture:让一个函数为测试提供输入,测试函数必须将该函数名称名称作为输入参数。
Pytest中fixture的几种用法
pytest.mark.parametrize:简化代码重复输入
4. 装饰器logger_decor, 显示函数调用和运行信息
from logger_decor import tron
@tron
def f(a, b=1, *args, **kwargs):
print('a: ', a)
print('b: ', b)
print('args: ', args)
print('kwargs:', kwargs)
return a + b
f(2, 3, 4, 5, c=6, d=7)
print()
f(2, c=5, d=6)
print()
f(10)
Calling f((2, 3, 4, 5), {'c': 6, 'd': 7})
a: 2
b: 3
args: (4, 5)
kwargs: {'c': 6, 'd': 7}
Finished f(5)
Elapsed time: 1.3589859008789062e-05
Calling f((2,), {'c': 5, 'd': 6})
a: 2
b: 1
args: ()
kwargs: {'c': 5, 'd': 6}
Finished f(3)
Elapsed time: 5.245208740234375e-06
Calling f((10,), {})
a: 10
b: 1
args: ()
kwargs: {}
Finished f(11)
Elapsed time: 4.291534423828125e-06