目录
pytest.mark.parametrize
mock.patch
pytest.mark.parametrize
现在有 zjk.py 模块,想测试其中 add 函数的功能,传入 x, y,把 x 平方后的结果与 y 相加返回。
zjk.py:
def power(x):
return x ** 2
def add(x ,y):
x = power(x)
return x + y
创建一个测试文件,测试文件一般以 test 开头或结尾,创建 test_zjk.py:
import pytest
from zjk import add
@pytest.mark.parametrize("pow_res, x, y, excepts", [
(4, 2, 5, 9),
(16, 4, 11, 27)
])
def test_add(pow_res, x, y, excepts):
res = add(x ,y)
assert res == excepts
在 pycharm 中可以单独运行测个测试函数:
运行结果没有报错,说明测试用例全都通过:
如果测试用例失败不符合预期结果,会报错提示是哪个用例不通过:
@pytest.mark.parametrize
这个是参数模拟设置用的函数,在此例中的测试函数传入了 4 个参数,其中 x,y 是必要的,其他两个是自己加的,因为 x,y 是要测的传入的值,另外两个一个是 x 平方后的值,一个是预期输出值,对应关系,这里是两组测试用例,及代表要运行 2 次:
调用 add 函数得到计算结果,关键字 assert 断言,判断结果与预期结果等不等,不等为 FAlse,会不通过用例,即上面的截图。
mock.patch
看上面的 zjk.py 里面 add 函数是调用了一个 power 函数的,而 add 是想测的函数,我们只想测这个函数的代码,中途调用的函数过程不想关心,想直接用它返回的值,因为万一 power 函数是一些网络请求,cmd 命令等,就需要网络,机器等,所以为了专注测试,用 patch 模拟 power 函数返回值
zjk.py 我们在其中再添加一个函数,并且 power 调用两次:
def power(x):
return x ** 2
def sub(y):
return y - 1
def add(x ,y):
x = power(x)
x1 = power(x)
y = sub(y)
return x1 + y
test.py 修改:
import mock
import pytest
from zjk import add
@pytest.mark.parametrize("x, y, excepts, pow_res, sub_res", [
(2, 5, 20, [4,16], 4),
(3, 4, 84, [9, 81], 3),
(7, 7, 2407, [49, 2401], 6)
])
@mock.patch("zjk.sub")
@mock.patch("zjk.power")
def test_add(mock_power, mock_sub, x, y, excepts, pow_res, sub_res):
mock_power.side_effect = pow_res
mock_power.return_value = pow_res
mock_sub.return_value = sub_res
res = add(x ,y)
assert res == excepts
添加了 @mock.patch,代表要测的 add 函数中间过程调用的函数,如 zjk.sub,这里表示传入的是sub 函数路径,之后需要在测试函数 test_add 传入函数,格式为 mock_函数名,且有顺序要求,传入参数顺序(左往右),装饰器顺序(下往上)
parametrize 中也需要添加 power,sub 函数的取值,就可以测试了
return_value 好理解就是设定返回值,如 mock_sub.return_value = sub_res 把 sub 函数的返回值进行赋值,但必须为数值型或字符串,罗被 mock 函数有多个返回值,也用它,且用元祖括起来,例如 mock-sub.return = (1, 2)
side_effect 赋值的要求必须是可迭代对象,意思就是同一个函数调用了多次,每次调用结果用列表存起来,并用 side_effect 赋值,表示每一次调用的取值
根据实际情况进行设置,用反了会报错
来看一下结果: