单元测试
: 在软件开发过程中,对软件的最小单位(函数、类等)进行正确性的检查测试(一般由开发人员完成)。是自动化测试的一部分。
java中常用junit / testng,
python 中常用unittest / pytest
单元测试框架的作用:从项目中的多个文件中找到测试用例,然后按照特定的顺序、规则依次执行,生成结果后使用断言方式判断是否符合预期;最后生成测试报告。
以上pytest库及插件的安装,可以使用递归式安装:
# 1. 将所有的库名字放入requirements.txt中
# pytest
# pytest-html
# ...
# 2. 递归安装
pip install -r requirements.txt
# -U 表示更新
# 查看
pytest --version
pytest --help
pytest默认的测试用例规则如下:
import pytest
# 模拟被测试函数单元
def func(a, b):
return a ** b
# 测试类 以Test开头,不能有init
class TestLaufing:
# 测试用例(方法),以test_开头
def test_func(self):
a, b = 2, 3
c = 8
assert c == func(a, b)
print("test func 成功")
def test_002(self):
assert 1 == 2
# 跳过如下测试用例
@pytest.mark.skip
def test_003(self):
assert 1 == 1
if __name__ == '__main__':
# 主函数方式执行
# 执行所有的测试用例
# 执行该模块即可
pytest.main()
测试结果如下:
. 代表测试通过;
F 代表测试失败;
s 代表测试用例跳过;
E 代表有异常;
测试用例的执行方法如下:
# 导包
import pytest
if __name__ == '__main__':
# 主函数方式执行
# 执行web_app目录下的所有测试用例
pytest.main(["-vs", "web_app"])
说明:
pytest.main() 执行所有的测试用例;
pytest.main([“-v”, “web_app”]) 执行该目录下的所有的测试用例;
pytest.main([“-v”, “./web_app/test_xxx.py”]) 执行该目录中指定模块的测试用例;
pytest.main([“-v”, “web_app/test_pytest_demo.py::TestWeb::test_func”]) 指定单个测试用例;
参数说明:
-v 输出详细信息;
-s 输出print打印的信息;
-vs 可以结合使用;
-n 多线程执行(必须安装pytest-xdist 插件);
pytest.main([‘-vs’, ‘app’, ‘-n=2’]) ;
pytest -vs app -n 2 ;
相当于有个两个线程的线程池,一次跑两个用例(两个线程)。
–maxfail=2 两个用例失败后退出测试;
pytest.main([“-vs”, “web_app”, “-n=2”, “–maxfail=2”])
-x 有一个测试用例失败即退出测试;
-q 删除更少的信息;
–reruns 5 失败用例的重跑(num次);需要安装pytest-rerunfailures
-k 匹配测试用例的部分字符串;匹配到则执行用例;
如 -k “_laufing”
unittest: 按照ASCII码执行;
pytest: 按照(测试类中的用例)从上到下的顺序;
要改变执行顺序:
# 测试类 以Test开头,不能有init
class TestWeb:
# 测试用例(方法),以test_开头
def test_func(self):
time.sleep(3)
a, b = 2, 3
c = 8
assert c == func(a, b)
print("test func 成功")
def test_002(self):
time.sleep(3)
assert 1 == 2
# 跳过如下测试用例
@pytest.mark.skip
def test_003(self):
assert 1 == 1
@pytest.mark.run(order=1)
def test_004(self):
time.sleep(3)
assert 1 == 2
它是pytest的核心配置文件,放在项目的根目录下;
pytest执行测试(不管主函数形式还是命令行形式)前,必先读取配置文件,可以改变其默认行为;
配置文件编码格式必须是ANSI,可以使用txt修改编码格式;
配置如下:
模块名、类名、函数名可以不按照默认的规则,实现随意命名。
使用mark标记,可以将不同模块的用例标记为一组,然后分组执行。
如下:
import pytest
# 模拟被测试函数单元
def func(a, b):
return a ** b
# 配置文件可以改变默认的行为
class TestAppClass:
# 测试用例(方法),以test_开头
def test_func(self):
a, b = 2, 3
c = 8
assert c == func(a, b)
print("test func 成功")
@pytest.mark.user1 # 标记为user1组
def test_app_002(self):
print("app_002: user1组")
assert 1 == 2
# 跳过如下测试用例
@pytest.mark.skip
def test_003(self):
assert 1 == 1
import pytest
# 模拟被测试函数单元
def func(a, b):
return a ** b
# 测试类 以Test开头,不能有init
class TestWebAppClass:
# 测试用例(方法),以test_开头
def test_func(self):
a, b = 2, 3
c = 8
assert c == func(a, b)
print("test func 成功")
@pytest.mark.user1 # 标记为user1组
def test_web_app_002(self):
print("web app: user1组")
assert 1 == 2
# 跳过如下测试用例
@pytest.mark.skip
def test_003(self):
assert 1 == 1
[pytest]
addopts = -vs
testpaths = ./
python_files = test_*.py
python_classes = Test*
python_functions = test
# 从以上选择到的用例中再选择分组
markers =
user1: user1 group
user2: user2 group
使用txt记事本打开,另存为修改编码方式
pytest -m 'user1'
# 执行多个分组
pytest -m 'user1 or user2'
# 无条件跳过
@pytest.mark.skip(reason="xxx")
def test_002(self):
assert 1 == 2
# 有条件的跳过
num = 6
@pytest.mark.skipif(num >= 5, reason="xxx")
def test_002(self):
assert 1 == 2
# 主函数形式
pytest.main(['-vs', '--html=./report.html', 'test_case'])
# 命令行
pytest -vs test_case --html ./report.html
# 配置文件
addopts = -vs --html ./report.html