pytest夹具fixture、常用插件和allure报告

1.pytest夹具fixture

夹具:在用例执行之前,执行之后,自动的运行代码

1.1 创建fixture

  1. python函数+fixture装饰器

前后之分:yield

1 import pytest
2 
3 @pytest.fixture
4 def func():
5     print('我是前置代码,在用例开始之前,执行【启动浏览器、链接数据库,创建测试数据...】')
6     yield
7     print('我是后置代码,在用例开始之后,执行【关闭浏览器、断开数据库、删除测试数据】')

1.2 使用fixture

1 def test_A(func):
2     #print('我开始执行用例') #启动浏览器
3     assert 1==1
4     #print('我执行结束了') #关闭浏览器

1.3 fixture的作用范围

pytest的fixture,支持5级作用域(unittest支持3级),让用例共享fixture

  1. function:每个用例不共享fixture的返回值,默认
  2. class:每个类中的用例,共享fixture
  3. module:每个模块(文件)中的用例,共享fixture
  4. package:每个包(目录)中的用例,共享fixture
  5. session:所有的用例,共享fixture

1.3.1 function

 1 import pytest
 2 
 3 @pytest.fixture(scope="function")
 4 def func():
 5     print('我是前置代码,在用例开始之前,执行【启动浏览器、链接数据库,创建测试数据...】')
 6     print('我开始执行用例') #启动浏览器
 7     yield
 8     print('我执行结束了') #关闭浏览器
 9     print('我是后置代码,在用例开始之后,执行【关闭浏览器、断开数据库、删除测试数据】')
10 
11 
12 @pytest.mark.skip
13 def test_A(func):
14     #print('我开始执行用例') #启动浏览器
15     assert 1==1
16     #print('我执行结束了') #关闭浏览器
17 
18 @pytest.mark.skip
19 def test_B(func):
20     #print('我开始执行用例') #连接数据库
21     assert 1 == 2
22     #print('我执行结束了') #关闭数据库连接
23 
24 @pytest.mark.skip
25 def test_C(func):
26     #print('我开始执行用例') #连接数据库
27     assert 3 == 3
28     #print('我执行结束了') #关闭数据库连接

1.3.2 class

 1 import pytest
 2 
 3 @pytest.fixture(scope="class")
 4 def func():
 5     print('我是前置代码,在用例开始之前,执行【启动浏览器、链接数据库,创建测试数据...】')
 6     print('我开始执行用例') #启动浏览器
 7     yield
 8     print('我执行结束了') #关闭浏览器
 9     print('我是后置代码,在用例开始之后,执行【关闭浏览器、断开数据库、删除测试数据】')
10 
11 
12 @pytest.mark.skip
13 def test_A(func):
14     #print('我开始执行用例') #启动浏览器
15     assert 1==1
16     #print('我执行结束了') #关闭浏览器
17 
18 @pytest.mark.skip
19 def test_B(func):
20     #print('我开始执行用例') #连接数据库
21     assert 1 == 2
22     #print('我执行结束了') #关闭数据库连接
23 
24 @pytest.mark.skip
25 def test_C(func):
26     #print('我开始执行用例') #连接数据库
27     assert 3 == 3
28     #print('我执行结束了') #关闭数据库连接
29 
30 
31 class TestA:
32     def test_a(self,func):
33         pass
34 
35     def test_b(self,func):
36         pass

1.3.3 module

 1 import pytest
 2 
 3 @pytest.fixture(scope="module")
 4 def func():
 5     print('我是前置代码,在用例开始之前,执行【启动浏览器、链接数据库,创建测试数据...】')
 6     print('我开始执行用例') #启动浏览器
 7     yield
 8     print('我执行结束了') #关闭浏览器
 9     print('我是后置代码,在用例开始之后,执行【关闭浏览器、断开数据库、删除测试数据】')
10 
11 
12 def test_A(func):
13     #print('我开始执行用例') #启动浏览器
14     assert 1==1
15     #print('我执行结束了') #关闭浏览器
16 
17 def test_B(func):
18     #print('我开始执行用例') #连接数据库
19     assert 1 == 2
20     #print('我执行结束了') #关闭数据库连接
21 
22 def test_C(func):
23     #print('我开始执行用例') #连接数据库
24     assert 3 == 3
25     #print('我执行结束了') #关闭数据库连接
26 
27 
28 class TestA:
29     def test_a(self,func):
30         pass
31 
32     def test_b(self,func):
33         pass

1.3.4 package

注意:需要把夹具文件conftest放在你需要的用例的目录,如果放在项目根路径,那package作用域和seesion作用域功能是一样的

 1 #test_abc.py
 2 
 3 import pytest
 4 
 5 
 6 class TestABC:
 7     @pytest.mark.ut
 8     def test_ok(self,func):
 9         assert 1 == 1
10 
11     @pytest.mark.ut
12     def test_fail(self,func):
13         assert 1 == 2
14 
15     @pytest.mark.skip #无条件跳过
16     @pytest.mark.ui
17     def test_web(self):
18         assert 1==3
19 
20     @pytest.mark.api
21     def test_api(self):
22         assert 2
23 
24     @pytest.mark.skipif(True,reason='为真时跳过') #无条件跳过
25     @pytest.mark.ui
26     def test_UI(self):
27         assert 3
28 
29     @pytest.mark.ui
30     @pytest.mark.xfail #预期失败
31     def test_app(self):
32         assert 4
33 
34 #test_add.py
35 
36 import pytest
37 
38 
39 def add(a, b):  # 计算a+b的结果
40     return a + b
41 
42 
43 @pytest.mark.parametrize(
44     "a,b",
45     [
46         (1, 1),
47         (3, 5),
48         ('3', '5'),
49         (None, '5'),
50         (None, False)
51     ]
52 )
53 def test_1(a, b,func):
54     # a = 1
55     # b = 1
56     c = add(a, b)
57     assert c == a + b
58 
59 #test_fixture.py
60 
61 import pytest
62 
63 def test_A(func):
64     #print('我开始执行用例') #启动浏览器
65     assert 1==1
66     #print('我执行结束了') #关闭浏览器
67 
68 def test_B(func):
69     #print('我开始执行用例') #连接数据库
70     assert 1 == 2
71     #print('我执行结束了') #关闭数据库连接
72 
73 def test_C(func):
74     #print('我开始执行用例') #连接数据库
75     assert 3 == 3
76     #print('我执行结束了') #关闭数据库连接
77 
78 
79 class TestA:
80     def test_a(self,func):
81         pass
82 
83     def test_b(self,func):
84         pass
85 
86 #conftest.py
87 
88 import pytest
89 
90 @pytest.fixture(scope="package")
91 def func():
92     print('我是前置代码,在用例开始之前,执行【启动浏览器、链接数据库,创建测试数据...】')
93     print('我开始执行用例') #启动浏览器
94     yield
95     print('我执行结束了') #关闭浏览器
96     print('我是后置代码,在用例开始之后,执行【关闭浏览器、断开数据库、删除测试数据】

1.3.5 session

 1 #test_abc.py
 2 
 3 import pytest
 4 
 5 
 6 class TestABC:
 7     @pytest.mark.ut
 8     def test_ok(self,func):
 9         assert 1 == 1
10 
11     @pytest.mark.ut
12     def test_fail(self,func):
13         assert 1 == 2
14 
15     @pytest.mark.skip #无条件跳过
16     @pytest.mark.ui
17     def test_web(self):
18         assert 1==3
19 
20     @pytest.mark.api
21     def test_api(self):
22         assert 2
23 
24     @pytest.mark.skipif(True,reason='为真时跳过') #无条件跳过
25     @pytest.mark.ui
26     def test_UI(self):
27         assert 3
28 
29     @pytest.mark.ui
30     @pytest.mark.xfail #预期失败
31     def test_app(self):
32         assert 4
33 
34 #test_add.py
35 
36 import pytest
37 
38 
39 def add(a, b):  # 计算a+b的结果
40     return a + b
41 
42 
43 @pytest.mark.parametrize(
44     "a,b",
45     [
46         (1, 1),
47         (3, 5),
48         ('3', '5'),
49         (None, '5'),
50         (None, False)
51     ]
52 )
53 def test_1(a, b,func):
54     # a = 1
55     # b = 1
56     c = add(a, b)
57     assert c == a + b
58 
59 #test_fixture.py
60 
61 import pytest
62 
63 def test_A(func):
64     #print('我开始执行用例') #启动浏览器
65     assert 1==1
66     #print('我执行结束了') #关闭浏览器
67 
68 def test_B(func):
69     #print('我开始执行用例') #连接数据库
70     assert 1 == 2
71     #print('我执行结束了') #关闭数据库连接
72 
73 def test_C(func):
74     #print('我开始执行用例') #连接数据库
75     assert 3 == 3
76     #print('我执行结束了') #关闭数据库连接
77 
78 
79 class TestA:
80     def test_a(self,func):
81         pass
82 
83     def test_b(self,func):
84         pass
85 
86 #conftest.py
87 
88 import pytest
89 
90 @pytest.fixture(scope="session")
91 def func():
92     print('我是前置代码,在用例开始之前,执行【启动浏览器、链接数据库,创建测试数据...】')
93     print('我开始执行用例') #启动浏览器
94     yield
95     print('我执行结束了') #关闭浏览器
96     print('我是后置代码,在用例开始之后,执行【关闭浏览器、断开数据库、删除测试数据】')

 共享fixture好处:

  1. 节省fixture的执行时间
    1. 每一个用例都启动浏览器,然后关闭浏览器 4000个用例*7秒=28000秒
    2. 全局只启动一次浏览器,供每个用例使用:1*7s=7s
  2. 用例之间传递数据  
 1 import pytest
 2 
 3 def test_A(func):
 4     #print('我开始执行用例') #启动浏览器
 5     assert 1==1
 6     func.id=15
 7     #print('我执行结束了') #关闭浏览器
 8 
 9 
10 class TestA:
11     def test_a(self,func):
12         id=func.id
13         print(id)
14         func.id+=1
15 
16     def test_b(self,func):
17         id=func.id
18         print(id)
19 
20 import pytest
21 
22 class clazz1:
23     pass
24 
25 @pytest.fixture(scope="session")
26 def func():
27     print('我是前置代码,在用例开始之前,执行【启动浏览器、链接数据库,创建测试数据...】')
28     print('我开始执行用例') #启动浏览器
29     yield clazz1()
30     print('我执行结束了') #关闭浏览器
31     print('我是后置代码,在用例开始之后,执行【关闭浏览器、断开数据库、删除测试数据】')

 共享fixture弊端:

  • 共享之后,不会重复执行(例如,用例执行过程中,浏览器意外关闭,就不会再次启动浏览器)

1.4 conftest.py

从名字上看:测试配置文件(代码版)

从功能上看:可以被所有的用例自动导入,用来存放跨文件的fixture、hook

  每个目录,都可以创建一个conftest.py,可以屏蔽上级目录的conftest.py

 哪个conftest.py离测试用例越近,影响力越大

应该在根目录创建通用的conftest

然后在个别目录,创建特殊的conftest

1.5 fixture的其他写法

 

https://mp.weixin.qq.com/s/iMQfm_7jwVFWD9cY2r94TA

2.pytest常用插件

有的插件,安装之后,自动启用

有的插件,安装之后,配置后才启用

2.1 pytest-html

用途:生成html报告

安装:pip install pytest-html

配置:

addopts= --html=report.html --self-contained-html

2.2 pytest-xdist

用途:并法执行用例

安装:pip install pytest-xdist

配置:

[pytest]
addopts= -n 4
addopts= -n auto
addopts=-n 0
  • 0 不使用并发
  • 4 创建4个进程并发
  • auto 创建和cpu相同数量的进程并发

2.3 pytest-rerunfailures

用途:用例失败之后,重新运行

安装:pip install pytest-rerunfailures

配置:

[pytest]
addopts= --reruns 5 --reruns-delay 1
1 import random
2 
3 
4 def test_abc():
5     a = random.randint(1, 5)
6     b = 5
7     assert a == b

2.4 pytest-order

用途:自定义用例执行顺序

安装:pip install pytest-order

 1 #test_order.py
 2 
 3 import pytest
 4 
 5 @pytest.mark.order(1)
 6 def test_a():
 7     pass
 8 
 9 @pytest.mark.order(3)
10 def test_b():
11     pass
12 
13 #test_new_order.py
14 import pytest
15 
16 @pytest.mark.order(2)
17 def test_c():
18     pass
19 
20 @pytest.mark.order(4)
21 def test_d():
22     pass

预期效果:a,c,b,d

排序规则:

  1. 先执行有order标记的用例,后执行没有order标记的用例
  2. order标记越小,顺序越靠前

2.5 pytest-result-log

用途:将用例的名称和结果,保存到日志文件

安装:pip install pytest-result-log

配置:

[pytest]

log_file= ./pytest.log
log_file_level= info
log_file_format= %(levelname)-8s %(asctime)s [%(name)s:%(lineno)s] : %(message)s
log_file_date_format=%Y-%m-%d %H:%M:%S

result_log_level_verbose=info

2.6 allure-pytest

allure是一个Java测试报告框架

allure-pytest:是allure支持pytest插件

用途:生成allure能够识别的数据文件

安装:pip install allure-pytest

配置:

[pytest]

addopts=--alluredir=./temp --clean-alluredir

3.allure企业级测试报告

allure:是一个java测试报告框架

3.1 搭建java的jdk环境

JDK+Java源程序

JDK:

  1. 使用Pycharm自带的java.exe
  2. 如果单独安装。建议使用JDK17+
  3. 设置环境变量:JAVA_HONE,PATH
  4. 命令可以执行java.exe

 E:\Program Files\JetBrains\PyCharm Community Edition 2023.1.2\jbr\bin

环境变量:

JAVA_HONE =E:\Program Files\JetBrains\PyCharm Community Edition 2023.1.2\jbr

PATH=PATH;E:\Program Files\JetBrains\PyCharm Community Edition 2023.1.2\jbr\bin

验证:

命令行窗口输入:java,能显示如截图一样的信息,说明环境变量设置成功

3.2 Allure环境搭建

1.解压 allure安装包

2.环境变量配置:PATH=PATH;D:\allure-2.24.1\bin\

3.命令行验证:allure

 pycharm分别执行:java和allure

3.3 生成报告

allure generate -c -o report temps

根据temps目录中的数据,生成报告并放在report目录中

allure seve temps

根据temps目录中的数据,生成报告并直接展示

3.4 内容定制

3.4.1 logo定制

3.4.1.1 启用插件

D:\allure-2.18.1\config\allure.yml

3.4.1.2 修改logo

D:\allure-2.18.1\plugins\custom-logo-plugin\static\styles.css

 url('要修改的文件.png')

文件放入styles.css同一目录

 重新生成报告

3.4.2 内容定制

 1 import pytest
 2 import allure
 3 
 4 @allure.epic('自动化测试项目')
 5 @allure.feature('模块A')
 6 @allure.story('场景.功能')
 7 @allure.title('用例A')
 8 @pytest.mark.order(1)
 9 def test_a():
10     pass
11 
12 @allure.epic('自动化测试项目')
13 @allure.feature('模块A')
14 @allure.story('场景.功能')
15 @allure.title('用例B')
16 @pytest.mark.order(3)
17 def test_b():
18     pass
19 
20 @allure.epic('自动化测试项目')
21 @allure.feature('模块B')
22 @allure.story('场景.功能')
23 @allure.title('用例C')
24 @pytest.mark.order(1)
25 def test_c():
26     pass
27 
28 @allure.epic('自动化测试项目')
29 @allure.feature('模块B')
30 @allure.story('场景.功能')
31 @allure.title('用例D')
32 @pytest.mark.order(3)
33 def test_d():
34     pass

posted @ 2024-01-07 15:48  万溪汇海  阅读(148)  评论(0编辑  收藏  举报