测试的种类
根据关注点不同,测试分为两大类acceptance tests: 也就说,测试需要完成的功能,是否都已经实现
unit test:测试程序中不同的模块,是否能够正常、正确的相互调用
这两大类里面,都包含以下三个方面:exploratory testing
regression testing
integration testing
测试程序
doctest
这是一个自动化的测试程序,你把你的测试命令写在 docstring 或者 readme.txt,这个 package 会帮你做测试。
举个栗子
"""
This is the "example" module.
The example module supplies one function, factorial(). For example,
>>> factorial(5)
120
"""
def factorial(n):
"""Return the factorial of n, an exact integer >= 0.
>>> [factorial(n) for n in range(6)]
[1, 1, 2, 6, 24, 120]
>>> factorial(30)
265252859812191058636308480000000
>>> factorial(-1)
Traceback (most recent call last):
...
ValueError: n must be >= 0
Factorials of floats are OK, but the float must be an exact integer:
>>> factorial(30.1)
Traceback (most recent call last):
...
ValueError: n must be exact integer
>>> factorial(30.0)
265252859812191058636308480000000
It must also not be ridiculously large:
>>> factorial(1e100)
Traceback (most recent call last):
...
OverflowError: n too large
"""
import math
if not n >= 0:
raise ValueError("n must be >= 0")
if math.floor(n) != n:
raise ValueError("n must be exact integer")
if n+1 == n: # catch a value like 1e300
raise OverflowError("n too large")
result = 1
factor = 2
while factor <= n:
result *= factor
factor += 1
return result
if __name__ == "__main__":
import doctest
doctest.testmod()
运行代码
python example.py -v
得到的结果如下
Trying:
factorial(5)
Expecting:
120
ok
Trying:
[factorial(n) for n in range(6)]
Expecting:
[1, 1, 2, 6, 24, 120]
ok
Trying:
factorial(1e100)
Expecting:
Traceback (most recent call last):
...
OverflowError: n too large
ok
2 items passed all tests:
1 tests in __main__
8 tests in __main__.factorial
9 tests in 2 items.
9 passed and 0 failed.
Test passed.
这种测试方法不适合大规模测试。
手工写测试
主要用到的语法是
try ... except ... 和 assert
比如
import sys
def test_quadroots_types():
try:
quad_roots("", "green", "hi")
except:
assert(sys.exc_info()[0] == TypeError)
test_quadroots_types()
import sys
def test_quadroots_zerocoeff():
try:
quad_roots(a=0.0)
except:
assert(sys.exc_info()[0] == ValueError)
test_quadroots_zerocoeff()
pytest
这里用实例来说明这个包怎么用。
首先,我们有一个 root 函数
%%file roots.py
def quad_roots(a=1.0, b=2.0, c=0.0):
"""Returns the roots of a quadratic equation: ax^2 + bx + c = 0.
INPUTS
=======
a: float, optional, default value is 1
Coefficient of quadratic term
b: float, optional, default value is 2
Coefficient of linear term
c: float, optional, default value is 0
Constant term
RETURNS
========
roots: 2-tuple of complex floats
Has the form (root1, root2) unless a = 0
in which case a ValueError exception is raised
EXAMPLES
=========
>>> quad_roots(1.0, 1.0, -12.0)
((3+0j), (-4+0j))
"""
import cmath # Can return complex numbers from square roots
if a == 0:
raise ValueError("The quadratic coefficient is zero. This is not a quadratic equation.")
else:
sqrtdisc = cmath.sqrt(b * b - 4.0 * a * c)
r1 = -b + sqrtdisc
r2 = -b - sqrtdisc
twoa = 2.0 * a
return (r1 / twoa, r2 / twoa)
然后写一个 test 文件
%%file test_roots.py
import pytest
import roots
def test_quadroots_result():
assert roots.quad_roots(1.0, 1.0, -12.0) == ((3+0j), (-4+0j))
def test_quadroots_types():
with pytest.raises(TypeError):
roots.quad_roots("", "green", "hi")
def test_quadroots_zerocoeff():
with pytest.raises(ValueError):
roots.quad_roots(a=0.0)
最后调用 pytest
python -m pytest ./test_roots.py
输出结果大概长这样
============================= test session starts ==============================
platform darwin -- Python 3.6.7, pytest-3.8.2, py-1.6.0, pluggy-0.7.1
rootdir: xx
plugins: remotedata-0.3.0, openfiles-0.3.0, doctestplus-0.1.3, cov-2.5.1, arraydiff-0.2
collected 3 items
test_roots.py ... [100%]
=========================== 3 passed in 0.03 seconds ===========================
pytest-cov
有时候,一个文件里面的函数很多,你希望确保所有的函数都被测试程序覆盖掉了。所以这个时候需要 pytest-cov 上场了。
%%file roots.py
def linear_roots(a=1.0, b=0.0):
"""Returns the roots of a linear equation: ax+ b = 0.
INPUTS
=======
a: float, optional, default value is 1
Coefficient of linear term
b: float, optional, default value is 0
Coefficient of constant term
RETURNS
========
roots: 1-tuple of real floats
Has the form (root) unless a = 0
in which case a ValueError exception is raised
EXAMPLES
=========
>>> linear_roots(1.0, 2.0)
-2.0
"""
if a == 0:
raise ValueError("The linear coefficient is zero. This is not a linear equation.")
else:
return ((-b / a))
def quad_roots(a=1.0, b=2.0, c=0.0):
"""Returns the roots of a quadratic equation: ax^2 + bx + c = 0.
INPUTS
=======
a: float, optional, default value is 1
Coefficient of quadratic term
b: float, optional, default value is 2
Coefficient of linear term
c: float, optional, default value is 0
Constant term
RETURNS
========
roots: 2-tuple of complex floats
Has the form (root1, root2) unless a = 0
in which case a ValueError exception is raised
EXAMPLES
=========
>>> quad_roots(1.0, 1.0, -12.0)
((3+0j), (-4+0j))
"""
import cmath # Can return complex numbers from square roots
if a == 0:
raise ValueError("The quadratic coefficient is zero. This is not a quadratic equation.")
else:
sqrtdisc = cmath.sqrt(b * b - 4.0 * a * c)
r1 = -b + sqrtdisc
r2 = -b - sqrtdisc
twoa = 2.0 * a
return (r1 / twoa, r2 / twoa)
然后加入还是只测试 quad_roots 这个函数,故意漏掉 linear_roots。看看 pytest-cov 能不能帮我们发现。
运行 python -m pytest ./test_roots.py --cov --cov-report term-missing
============================= test session starts ==============================
platform darwin -- Python 3.6.7, pytest-3.8.2, py-1.6.0, pluggy-0.7.1
rootdir: xx
plugins: remotedata-0.3.0, openfiles-0.3.0, doctestplus-0.1.3, cov-2.5.1, arraydiff-0.2
collected 3 items
test_roots.py ... [100%]
---------- coverage: platform darwin, python 3.6.7-final-0 -----------
Name Stmts Miss Cover Missing
---------------------------------------------
roots.py 13 3 77% 22-25
test_roots.py 10 0 100%
---------------------------------------------
TOTAL 23 3 87%
=========================== 3 passed in 0.04 seconds ===========================
可以告诉你 line 22-25 没有 cover 到。