A. 与unittest对比?
基于unittest之上的单元测试框架。
1)自动发现测试模块和测试方法
2) 断言使用assert+表达式即可
3) 可以设置测试会话级、模块级、函数级的fixtures数据准备+清理工作;
4) 有丰富的插件库,目前有600个以上。 ==allure
B. 安装
安装命令:pip install pytest
安装html报告的插件:pip install pytest-html
pytest插件地址:http://plugincompat.herokuapp.com/
C. Pytest收集测试用例的规则
1) 默认从当前目录中搜集用例,即在那个目录下运行pytest命令,则从那个目录当中搜索
2) 搜索规则:
a. 符合规则”test_*.py“或者”*_test.py“的文件
b. 以"test_"开头的函数名
c. 以Test开头的测试类(没有__init__函数)当中,以"test_"开头的函数名;
d. 用例可能会有多层,包名无限制
对测试用例打标签,在运行用例的时候,可根据标签名来过滤要运行的用例
使用方法:
1) 注册标签名
注册步骤:
1) 创建一个pytest.ini文件(建议:尽量放在项目目录下,其他位置也可以,pytest会从项目目录开始寻找),在文件中按照如下形式加标签名:
[pytest]
markers=
slow:marks tests as slow(deselect with "not slow")
smoke: test some important cases
uaual: some cases tested often waste much time
注意:冒号之后是标签的描述信息
2) 在测试用例/测试类前面加上: @pytest.mark.标记名
( 测试类上打的标记会被同样打在该测试类中的每一个方法,
一个测试类或测试函数可以有多个标签)
3) 根据用例标签筛选出指定用例并运行
(参考:3. Pytest之命令运行功能 )
1) 可以在用例目录下,新建一个py文件,内容如下:
if __name__=="__main__":
pytest.main()
# 也可以下边这种方式
pytest.main(["-s","-v"])
2) dos命令窗口,进入到用例目录下,然后:执行用例会比pytest.mian()输出结果更详细
python 命令敲入回车,也可执行用例
pytest -s -v 命令敲入回车,执行用例会比pytest输出结果更详细
3) 筛选用例进行执行
a. 执行all标签的用例
- 编辑器中(Pycharm):
if __name__=="__main__":
pytest.main(["-s","-v","-m","all"])
- dos窗口中,命令行参数:
pytest -s -v -m all
b. 执行多个标签的用例,如标签:all和test1和test2
- 编辑器中(Pycharm):
if __name__=="__main__":
pytest.main(["-s","-v","-m","all or test1 or test2"])
- dos窗口中,命令行参数:
pytest -s -v -m "all or test1 or test2”
注意: pytest命令在那个目录执行,那就以此目录韦根目录,按照规则自行去搜索用例
a. 前置后置共享函数定义
新建一个conftest.py文件,在测试用例目录下,在该文件当中,假如定义一个函数:init_def:
@pytest.fixture(scope="function")
def init_def():
print("函数前置")
yield
print("函数后置")
在 @pytest.fixture(scope="function"),
scope=function则代表测试用例的前置后置(即setUp和tearDown函数)
scope=class,代表测试类前置后置(即@classmethod装饰的setUpClass和tearDownClass函数);
scope=module, 代表py模块的前置后置,在模块中调用时,如果在第一个用例前用了,那么该模块会用,如果非第一个模块使用,那么该前置后置的作用域则在该用例及其之后(在执行第一个用例前不执行前置;
scope=session, 代表夹的是所有用例
(注意,如果@pytest.fixture()的参数除了scope,常用的还有
autouse : 代表无需调用,直接使用,如果是测试函数内部使用,则需要将该前后置函数名作为变量放到测试函数参数中,测试函数内部就可以直接使用了
b. 前置后置函数的调用
在测试类中,假设存在一个登录测试类:TestLogin,调用时,就在该测试类上方加入一行: @pytest.mark.usefixtures("init_def"),即:
使用@pytest.mark.usefixtures("init_def")装饰测试类TestLogin
注意: 如果说前置后置中的变量,测试类的测试用例会用到,那么需要:
a). 前置后置函数定义时,yiled 变量名
@pytest.fixture(scope="function")
def init_def():
c= 3
print("函数前置")
yield c
print("函数后置")
@pytest.fixture(scope="class")
def init_class_1():
a= 3
b=4
print("函数前置")
yield a,b # 返回的是一个元组
print("函数后置")
b). 测试函数调用时,需要
- 测试类被装饰:@pytest.mark.usefixtures("init_def")
- 测试函数内部调用变量时:
-- 函数定义参数中需要传入“前置后置函数名”,且内部调用情况如下
如: def test_add(self,init_def):
assert init_def>3
另一种,返回多个值
- 测试类被装饰:@pytest.mark.usefixtures("init_def_1")
- 测试函数内部调用变量时:
-- 函数定义参数中需要传入“前置后置函数名”,且内部调用情况如下
如: def test_add(self,init_class_1):
# init_def_1是一个元组
assert init_class[0]>3
)
注意: 测试类其实可以同时使用init_class_1和init_def
@pytest.mark.usefixtures("init_def")
@pytest.mark.usefixtures("init_class_1")
class TestLogin:
def test_add(self,init_def):
assert init_def>3
def test_add(self,init_class_1):
# init_class_1是一个元组
assert init_class[0]>3
注意: scope=module, 代表py模块的前置后置,在模块中调用时,如果在第一个用例前用了,那么该模块会用,如果非第一个模块使用,那么该前置后置的作用域则在该用例及其之后(在执行第一个用例前不执行前置
存在疑问: 如果setUp()中用到了setUpClass()中的变量该怎么办?(待续) 注意误区: (setuUp不允许如下写法):
@pytest.mark.usefixtures(“init_def”)
@pytest.mark.usefixtures(“init_class_1”)
class TestLogin:
def setup(self, init_class_1):
print(init_class_1)
def test_add(self,init_def):
assert init_def>3
问题解决方案:
(前后置函数继承中的: 函数级别继承类级别的fixture前后置函数,就可解决上述问题)
import pytest
'''
a. 同级别fixture继承,那么执行顺序如下:
被继承者前置---》继承者前置---》 (测试用例执行) ----》继承者后置----》被继承者后置(当继承多层的话,也是以此类推)
(同级别的话, 包含,函数继承函数,类继承类级别的fixture前后置函数)
b. 函数级别继承了类级别的fixture前后置函数:
被继承者前置---》(测试用例执行部分:
继承者前置---》执行用例1 》继承者后置----》
继承者前置---》执行用例2 》继承者后置----》
继承者前置---》执行用例1 》继承者后置----》
......
---》被继承者后置
《注意》 在这里,如果setUp用到了setUpClass中的内容,
且改变了,那么我们可创建一个变量用来接收setUpClass返回内容,修改相关内容,返回这个变量,接下来测试类引用后,就用的是改变之后的数据了(适用于driver对象)
一般常用的就是上述两种继承,其他也可以去尝试
'''
可看如下实例:
a. conftest中存在如下定义的函数:
# 被继承者函数
@pytest.fixture(scope="function")
def init_function_1():
a = 3
b = 4
print("==============函数前置==================")
yield a, b
print("==============函数后置==============")
@pytest.fixture(scope="class")
def init_class_11():
a = 3
b = 4
print("==============类前置==================")
yield a, b
print("==============类后置==============")
# 继承函数
# 函数级别的fixture函数 继承函数级别的fixture函数
@pytest.fixture(scope="function")
def init2_function_1(init_function_1):
a = 10
print("py模块内的init2--函数前置")
yield a, init_function_1
print("py模块内的init2--函数后置")
# 函数级别的fixture函数 继承“类”级别的fixture函数
@pytest.fixture(scope="function")
def init2_function_2(init_class_11):
a = 10
print("py模块内的init2--函数前置")
yield a, init_class_11
print("py模块内的init2--函数后置")
# 类的fixture函数 继承“类”级别的fixture函数
@pytest.fixture(scope="class")
def init2_class_2(init_class_11):
a = 10
print("py模块内的init2--类前置")
yield a, init_class_11
print("py模块内的init2--类后置")
b. 测试py模块中内容如下:
# @pytest.mark.usefixtures("init2_function_1")
# @pytest.mark.usefixtures("init2_function_2")
@pytest.mark.usefixtures("init2_class_2")
class TestPyFixture1:
# def test_fixture_1(self, init2_function_1):
# print("用例1")
# print(init2_function_1)
def test_fixture_2(self):
print("用例2")
def test_fixture_3(self):
print("用例3")
'''
如果fixture前置后置函数写在某个py模块中,那么:
a. 它的作用域就是该py模块
b. 如果autouse不是True,则需要在测试类或测试函数调用之后才可以使用(测试用例如果需要用到,那就fixture函数名当作参数传入用例函数中)
c. 如果autouse是True,可以直接使用(测试用例如果需要用到,那就fixture函数名当作参数传入用例函数中)
代码如下 :
'''
import pytest
@pytest.fixture(scope="function")
def init_function_1():
a = 3
b = 4
print("==============函数前置==================")
yield a, b
print("==============函数后置==============")
@pytest.fixture(scope="class")
def init_class_11():
a = 3
b = 4
print("==============类前置==================")
yield a, b
print("==============类后置==============")
# Py模块代码如下:
@pytest.fixture(scope="function")
def init1():
a = 10
print("py模块内的init前置")
yield a
print("py模块内的init后置")
@pytest.mark.usefixtures("init1")
class TestPyFixture:
def test_fixture_1(self, init1):
print(init1)
def test_fixture_2(self):
pass
pytest层级覆盖,测试用例与其同级或者在其子目录
Pycharm右上角运行窗口左侧的”倒三角“符号点击--Edit Configurations->Defaults---->Pytest tests点击---> 点击“+”--->选择“Python tests”---->选择“pytest”/"py.test"--->选择项目路径--->完成 点击即可
在测试用例前面加上: @pytest.mark.parametrize("参数名",列表数据)
参数名: 用来接收每一项数据,并用作测试用例参数
列表数据: 一组测试数据
@pytest.mark.parametrize("参数1,参数2",[(数据1,数据2),(数据1,数据2)....])
实例:
import pytest
# 前后置函数
@pytest.fixture(scope="function")
def init_1():
c = 8
yield c
# 测试函数
@pytest.mark.usefixtures("init_1")
class TestPytestDdt:
""" pytest参数化运用---类似ddt"""
cases_data = [(1, 0), (-1, 0), (0, 0), (1, -1)]
@pytest.mark.parametrize('a,b', cases_data)
def test_sum(self, a, b, init_1):
sum = a + b + init_1
assert sum == a + b + init_1
@pytest.mark.parametrize('a,b', cases_data)
def test_sum_1(self, a, b):
sum = a + b
assert sum == a + b
@pytest.mark.parametrize("a", cases_data)
def test_sum_2(self, a):
sum = a[0] + a[1]
assert sum == a[0] + a[1]
# 1). 执行testddt和testfixture标签的用例
# pytest.main(["-m", "testddt or testfixture",
# r"--html=reports\testReport.html"])
# pytest.main(["-s", "-v", "-m", "testddt or testfixture",
# r"--html=reports\testReport.html"])
# 2). 用例全量运行
# pytest.main([r"--html=reports\testReport.html"])
# 运行指定python包下的用例
# pytest.main(["-v", r"Cases/caseq/"])
# 3). 运行指定py模块下的用例
# pytest.main(["-v", r"Cases/caseq/test_add.py"])
# 4). 运行指定类的用例
# pytest.main(["-v", r"Cases/caseq/test_add.py::TestClss"])
# 5). 运行指定模块中指定函数名用例(检测不到测试类中同函数名的测试用例)
# pytest.main(["-v", r"Cases/caseq/test_add.py::test_add_3"])
# 6). 运行指定模块中指定内的指定用例
pytest.main(["-v", r"Cases/caseq/test_add.py::TestClss::test_add_3"])
(涉及路径的都是相对路径)
需要安装pytest-html: pip install pytest-html
pytest可以生成多种样式的结果
1) 生成JunitXML格式的测试报告, 命令 --junitxml=path
(方便其他平台解析测试结果)
2) 生成result log格式的测试报告,命令:--resultlog=report\log.txt
3) 生成html格式的测试报告,命令: --html=report\test_one_func.html(相对路径)
import pytest
if __name__ == "__main__": # 主函数入口
# 执行testddt和testfixture标签的用例
# pytest.main(["-m", "testddt or testfixture",
# r"--html=reports\testReport.html"])
# pytest.main(["-s", "-v", "-m", "testddt or testfixture",
# r"--html=reports\testReport.html"])
(官方学习地址: http://allure.qatools.ru/)
1) 从Maven Center下载最新的安装包(手动安装):
http://repo.maven.apache.org/maven2/io/qameta/allure/allure-commandline/
2) 将包解压到任何一个目录。进入到解压后的bin目录下面,windows下执行allure.bat
3) 系统变量新建: ALLURE_HOME = 解压路径
Path中追加: %ALLURE_HOME%\bin
(cmd窗口 allure --version来查看环境是否配置好)
4) 安装pytest的allure支撑插件
pip install allure-pytest
1) 执行pytest命令时,添加allure命令参数:--alluredir=Outputs/allure (相对于pytest命令所在目录的测试报告目录)
if __name__ == '__main__':
pytest.main(["-s","-v","--html=Outputs/reports/pytest.html",
"--alluredir=Outputs/allure"]) # allure文件生成的目录
2) 等待pytest执行完所有的测试用例,在Outputs/allure下会生成一些文件
在cmd命令行当中,处于当前项目测试目录, 执行: “allure serve 测试结果文件目录” 命令就会生成漂亮的html报告
Master/Slave模式:
分担Jekins服务器压力,任务分配到其他执行机来执行
Master: Jekins服务器
Slave: 执行机(奴隶机),执行Master分配的任务,并返回任务进度和结果
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4KhdKCGq-1600170492795)(C:\Users\Lujier\AppData\Roaming\Typora\typora-user-images\1575371500804.png)]
集成步骤如下(参考链接: http://www.lemfix.com/topics/348):
Step1: 去jenkins插件网站上下载allure插件最新版本:
http://mirrors.jenkins-ci.org/plugins/allure-jenkins-plugin/
Step2: 打开jenkins,在系统管理 —> 插件管理 —>Advanced —> Upload Plugin
上传.phi格式的插件,点击[上传]操作。