pytest-platform-adapter 1.0.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- pytest_platform_adapter-1.0.0/LICENSE +21 -0
- pytest_platform_adapter-1.0.0/PKG-INFO +243 -0
- pytest_platform_adapter-1.0.0/README.md +208 -0
- pytest_platform_adapter-1.0.0/pyproject.toml +50 -0
- pytest_platform_adapter-1.0.0/setup.cfg +4 -0
- pytest_platform_adapter-1.0.0/src/pytest_platform_adapter/__init__.py +0 -0
- pytest_platform_adapter-1.0.0/src/pytest_platform_adapter/plugin.py +265 -0
- pytest_platform_adapter-1.0.0/src/pytest_platform_adapter.egg-info/PKG-INFO +243 -0
- pytest_platform_adapter-1.0.0/src/pytest_platform_adapter.egg-info/SOURCES.txt +11 -0
- pytest_platform_adapter-1.0.0/src/pytest_platform_adapter.egg-info/dependency_links.txt +1 -0
- pytest_platform_adapter-1.0.0/src/pytest_platform_adapter.egg-info/entry_points.txt +2 -0
- pytest_platform_adapter-1.0.0/src/pytest_platform_adapter.egg-info/requires.txt +2 -0
- pytest_platform_adapter-1.0.0/src/pytest_platform_adapter.egg-info/top_level.txt +1 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 blackyau
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,243 @@
|
|
|
1
|
+
Metadata-Version: 2.2
|
|
2
|
+
Name: pytest_platform_adapter
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: Pytest集成自动化平台插件
|
|
5
|
+
Author-email: BlackYau <blackyau426@gmail.com>
|
|
6
|
+
Maintainer-email: BlackYau <blackyau426@gmail.com>
|
|
7
|
+
License: MIT
|
|
8
|
+
Project-URL: Homepage, https://github.com/blackyau/pytest-platform-adapter
|
|
9
|
+
Project-URL: Repository, https://github.com/blackyau/pytest-platform-adapter.git
|
|
10
|
+
Project-URL: Issues, https://github.com/blackyau/pytest-platform-adapter/issues
|
|
11
|
+
Keywords: pytest,platform,adapter,自动化平台,插件
|
|
12
|
+
Classifier: Development Status :: 5 - Production/Stable
|
|
13
|
+
Classifier: Environment :: Plugins
|
|
14
|
+
Classifier: Framework :: Pytest
|
|
15
|
+
Classifier: Intended Audience :: Developers
|
|
16
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
17
|
+
Classifier: Natural Language :: Chinese (Simplified)
|
|
18
|
+
Classifier: Programming Language :: Python :: 3
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.6
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.7
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.8
|
|
22
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
23
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
24
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
25
|
+
Classifier: Topic :: Software Development
|
|
26
|
+
Classifier: Topic :: Software Development :: Testing
|
|
27
|
+
Classifier: Topic :: Software Development :: Testing :: Acceptance
|
|
28
|
+
Classifier: Topic :: Software Development :: Libraries
|
|
29
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
30
|
+
Requires-Python: >=3.6
|
|
31
|
+
Description-Content-Type: text/markdown
|
|
32
|
+
License-File: LICENSE
|
|
33
|
+
Requires-Dist: pytest>=6.2.5
|
|
34
|
+
Requires-Dist: allure-pytest>=2.9.45
|
|
35
|
+
|
|
36
|
+
# pytest-platform-adapter
|
|
37
|
+
|
|
38
|
+
[](https://pypi.python.org/pypi/pytest-platform-adapter)
|
|
40
|
+
[](https://pypi.python.org/pypi/pytest-platform-adapter)
|
|
41
|
+
[](https://github.com/allure-framework/allure-python/actions/workflows/build.yaml)
|
|
42
|
+
|
|
43
|
+
Pytest集成自动化平台插件
|
|
44
|
+
|
|
45
|
+
## 功能
|
|
46
|
+
|
|
47
|
+
- 根据用例 `allure.title` 中的 ID 筛选执行的用例
|
|
48
|
+
- 跳过所有用例的执行,快速生成 Allure 报告
|
|
49
|
+
- 周期性的通过 RESTApi 上报执行用例的整体进度
|
|
50
|
+
|
|
51
|
+
## 环境依赖
|
|
52
|
+
|
|
53
|
+
- Python >= 3.6
|
|
54
|
+
- pytest >= 7.1.2
|
|
55
|
+
- allure-pytest >= 2.9.45
|
|
56
|
+
|
|
57
|
+
## 安装
|
|
58
|
+
|
|
59
|
+
执行以下命令即可完成安装
|
|
60
|
+
|
|
61
|
+
```shell
|
|
62
|
+
pip install pytest-platform-adapter
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
## 使用方法
|
|
66
|
+
|
|
67
|
+
### 根据 Allure title 中的 ID 筛选用例
|
|
68
|
+
|
|
69
|
+
假设有以下测试用例
|
|
70
|
+
|
|
71
|
+
```python
|
|
72
|
+
import allure
|
|
73
|
+
|
|
74
|
+
@allure.title('19936-测试用例1')
|
|
75
|
+
def test_case1():
|
|
76
|
+
assert True
|
|
77
|
+
|
|
78
|
+
@allure.title('19930-测试用例2')
|
|
79
|
+
def test_case2():
|
|
80
|
+
assert True
|
|
81
|
+
|
|
82
|
+
@allure.title('19939-测试用例3')
|
|
83
|
+
def test_case3():
|
|
84
|
+
assert True
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
该插件提供两种方式来筛选测试用例:
|
|
88
|
+
|
|
89
|
+
1. 通过命令行参数指定测试ID:
|
|
90
|
+
```bash
|
|
91
|
+
pytest tests/ -v --case-ids="19936,19930"
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
2. 通过文件指定测试ID:
|
|
95
|
+
```bash
|
|
96
|
+
pytest tests/ -v --case-ids-file="test_ids.txt"
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
其中 test_ids.txt 的内容格式如下:
|
|
100
|
+
```
|
|
101
|
+
19936
|
|
102
|
+
19930
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
### 跳过所有用例
|
|
106
|
+
|
|
107
|
+
使用 `--scan` 参数,启用扫描模式。在扫描模式下,所有用例都会被 skip 不会执行,可以用于快速生成 Allure 报告。使用方法如下:
|
|
108
|
+
|
|
109
|
+
```shell
|
|
110
|
+
pytest --scan --alluredir allure-results
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
### 将执行进展通过RESTApi回报
|
|
114
|
+
|
|
115
|
+
在 pytest.ini 中配置以下内容
|
|
116
|
+
|
|
117
|
+
```ini
|
|
118
|
+
[pytest]
|
|
119
|
+
platform_ip = 127.0.0.1
|
|
120
|
+
platform_port = 8080
|
|
121
|
+
platform_path = /api/autoplatform/task/refresh_data_count
|
|
122
|
+
platform_use_https = False
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
执行用例的过程中(前 10 个用例的时候执行完就立刻回报,之后就是每隔 10 个用例才回报一次) 会将测试用例的整体进展以 `POST` 的方式回报给 `http://127.0.0.1:8080/api/autoplatform/task/refresh_data_count` 请求体如下:
|
|
126
|
+
|
|
127
|
+
```json
|
|
128
|
+
{
|
|
129
|
+
"pipeline": "JOB_NAME",
|
|
130
|
+
"build_number": "BUILD_NUMBER",
|
|
131
|
+
"passed_case_count": 29,
|
|
132
|
+
"skipped_case_count": 1,
|
|
133
|
+
"failed_case_count": 0,
|
|
134
|
+
"selected_case": 100
|
|
135
|
+
}
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
其中 `JOB_NAME` 和 `BUILD_NUMBER` 是通过环境变量获取的。
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
## 调试方法
|
|
142
|
+
|
|
143
|
+
### 部署虚拟环境
|
|
144
|
+
|
|
145
|
+
新建一个虚拟环境,建议使用 Python 3.11.9 。
|
|
146
|
+
|
|
147
|
+
安装依赖
|
|
148
|
+
|
|
149
|
+
```shell
|
|
150
|
+
pip install -r requirements.txt
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
在项目根目录(与pyproject.toml同一路径)执行以下命令安装本插件
|
|
154
|
+
|
|
155
|
+
```shell
|
|
156
|
+
pip install -e .
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
执行 `pytest --help` 检查返回的内容是否包含以下文本,如果有的话就说明安装成功了
|
|
160
|
+
|
|
161
|
+
```
|
|
162
|
+
usage: pytest [options] [file_or_dir] [file_or_dir] [...]
|
|
163
|
+
|
|
164
|
+
positional arguments:
|
|
165
|
+
file_or_dir
|
|
166
|
+
|
|
167
|
+
general:
|
|
168
|
+
|
|
169
|
+
..... 省略中间
|
|
170
|
+
|
|
171
|
+
自动化平台插件:
|
|
172
|
+
--case_ids=CASE_IDS 要执行的测试用例ID列表,使用逗号分隔,例如:19936,19930
|
|
173
|
+
--case_ids_file=CASE_IDS_FILE
|
|
174
|
+
包含测试用例ID的文件路径,文件中每行一个ID
|
|
175
|
+
--scan 扫描模式:快速生成 Allure 报告而不实际执行测试
|
|
176
|
+
|
|
177
|
+
[pytest] ini-options in the first pytest.ini|tox.ini|setup.cfg|pyproject.toml file found:
|
|
178
|
+
|
|
179
|
+
..... 省略中间
|
|
180
|
+
|
|
181
|
+
platform_ip (string): 自动化平台IP
|
|
182
|
+
platform_port (string):
|
|
183
|
+
自动化平台端口
|
|
184
|
+
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
### 创建测试用例
|
|
188
|
+
|
|
189
|
+
在项目根目录新建 tests 目录,然后在 tests 目录中新建以 test_ 开头的 py 文件,作为测试用例。
|
|
190
|
+
|
|
191
|
+
例如新建 `test_aaa.py`,在文件中写入以下内容
|
|
192
|
+
|
|
193
|
+
```python
|
|
194
|
+
import allure
|
|
195
|
+
|
|
196
|
+
|
|
197
|
+
class TestAbc:
|
|
198
|
+
@allure.title('19936-用例1')
|
|
199
|
+
def test_abc(self):
|
|
200
|
+
print('test_abc 用例执行中')
|
|
201
|
+
|
|
202
|
+
# @pytest.mark.xfail(reason='跳过')
|
|
203
|
+
class TestAbd:
|
|
204
|
+
@allure.title('19930-用例2')
|
|
205
|
+
def test_abd(self):
|
|
206
|
+
with allure.step('步骤1'):
|
|
207
|
+
pass
|
|
208
|
+
|
|
209
|
+
# @pytest.mark.xfail(reason='跳过')
|
|
210
|
+
class TestAbe:
|
|
211
|
+
@allure.title('19932-用例3')
|
|
212
|
+
def test_abe(self):
|
|
213
|
+
pass
|
|
214
|
+
# raise AssertionError()
|
|
215
|
+
# pytest.fail('用例失败')
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
### 配置执行入口
|
|
219
|
+
|
|
220
|
+
然后再项目根目录新建 main.py 作为执行的入口,写入以下内容。
|
|
221
|
+
|
|
222
|
+
```python
|
|
223
|
+
import pytest
|
|
224
|
+
import os
|
|
225
|
+
import shutil
|
|
226
|
+
|
|
227
|
+
if __name__ == '__main__':
|
|
228
|
+
pytest_options = [
|
|
229
|
+
'tests/',
|
|
230
|
+
# '--case_ids', '456456',
|
|
231
|
+
# '--scan',
|
|
232
|
+
'-v',
|
|
233
|
+
'--alluredir', 'allure-results']
|
|
234
|
+
# shutil.rmtree('allure-results') # 如果需要清空 allure-results 目录就解除本行注释
|
|
235
|
+
pytest.main(pytest_options)
|
|
236
|
+
os.system('allure generate allure-results -o ./report --clean')
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
通过为 main.py 中的 pytest_options 列表,添加 `--case_ids` 参数可以排除指定的用例,添加或删除 `--scan` 参数可以启用或禁用扫描模式。
|
|
240
|
+
|
|
241
|
+
> 注意:如果发现 pytest_runtest_logreport 中的逻辑没有被执行。那可能是没有用例被选中(也就是本次没有执行任何用例)
|
|
242
|
+
|
|
243
|
+
修改 `plugin.py` 的话不用重新 `pip install` 安装本插件,它是实时生效的。因为 `pip install -e` 的本质是在 Python 解释器的 `site-packages` 里面做了一个软链接到了本项目。
|
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
# pytest-platform-adapter
|
|
2
|
+
|
|
3
|
+
[](https://pypi.python.org/pypi/pytest-platform-adapter)
|
|
5
|
+
[](https://pypi.python.org/pypi/pytest-platform-adapter)
|
|
6
|
+
[](https://github.com/allure-framework/allure-python/actions/workflows/build.yaml)
|
|
7
|
+
|
|
8
|
+
Pytest集成自动化平台插件
|
|
9
|
+
|
|
10
|
+
## 功能
|
|
11
|
+
|
|
12
|
+
- 根据用例 `allure.title` 中的 ID 筛选执行的用例
|
|
13
|
+
- 跳过所有用例的执行,快速生成 Allure 报告
|
|
14
|
+
- 周期性的通过 RESTApi 上报执行用例的整体进度
|
|
15
|
+
|
|
16
|
+
## 环境依赖
|
|
17
|
+
|
|
18
|
+
- Python >= 3.6
|
|
19
|
+
- pytest >= 7.1.2
|
|
20
|
+
- allure-pytest >= 2.9.45
|
|
21
|
+
|
|
22
|
+
## 安装
|
|
23
|
+
|
|
24
|
+
执行以下命令即可完成安装
|
|
25
|
+
|
|
26
|
+
```shell
|
|
27
|
+
pip install pytest-platform-adapter
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## 使用方法
|
|
31
|
+
|
|
32
|
+
### 根据 Allure title 中的 ID 筛选用例
|
|
33
|
+
|
|
34
|
+
假设有以下测试用例
|
|
35
|
+
|
|
36
|
+
```python
|
|
37
|
+
import allure
|
|
38
|
+
|
|
39
|
+
@allure.title('19936-测试用例1')
|
|
40
|
+
def test_case1():
|
|
41
|
+
assert True
|
|
42
|
+
|
|
43
|
+
@allure.title('19930-测试用例2')
|
|
44
|
+
def test_case2():
|
|
45
|
+
assert True
|
|
46
|
+
|
|
47
|
+
@allure.title('19939-测试用例3')
|
|
48
|
+
def test_case3():
|
|
49
|
+
assert True
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
该插件提供两种方式来筛选测试用例:
|
|
53
|
+
|
|
54
|
+
1. 通过命令行参数指定测试ID:
|
|
55
|
+
```bash
|
|
56
|
+
pytest tests/ -v --case-ids="19936,19930"
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
2. 通过文件指定测试ID:
|
|
60
|
+
```bash
|
|
61
|
+
pytest tests/ -v --case-ids-file="test_ids.txt"
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
其中 test_ids.txt 的内容格式如下:
|
|
65
|
+
```
|
|
66
|
+
19936
|
|
67
|
+
19930
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
### 跳过所有用例
|
|
71
|
+
|
|
72
|
+
使用 `--scan` 参数,启用扫描模式。在扫描模式下,所有用例都会被 skip 不会执行,可以用于快速生成 Allure 报告。使用方法如下:
|
|
73
|
+
|
|
74
|
+
```shell
|
|
75
|
+
pytest --scan --alluredir allure-results
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
### 将执行进展通过RESTApi回报
|
|
79
|
+
|
|
80
|
+
在 pytest.ini 中配置以下内容
|
|
81
|
+
|
|
82
|
+
```ini
|
|
83
|
+
[pytest]
|
|
84
|
+
platform_ip = 127.0.0.1
|
|
85
|
+
platform_port = 8080
|
|
86
|
+
platform_path = /api/autoplatform/task/refresh_data_count
|
|
87
|
+
platform_use_https = False
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
执行用例的过程中(前 10 个用例的时候执行完就立刻回报,之后就是每隔 10 个用例才回报一次) 会将测试用例的整体进展以 `POST` 的方式回报给 `http://127.0.0.1:8080/api/autoplatform/task/refresh_data_count` 请求体如下:
|
|
91
|
+
|
|
92
|
+
```json
|
|
93
|
+
{
|
|
94
|
+
"pipeline": "JOB_NAME",
|
|
95
|
+
"build_number": "BUILD_NUMBER",
|
|
96
|
+
"passed_case_count": 29,
|
|
97
|
+
"skipped_case_count": 1,
|
|
98
|
+
"failed_case_count": 0,
|
|
99
|
+
"selected_case": 100
|
|
100
|
+
}
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
其中 `JOB_NAME` 和 `BUILD_NUMBER` 是通过环境变量获取的。
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
## 调试方法
|
|
107
|
+
|
|
108
|
+
### 部署虚拟环境
|
|
109
|
+
|
|
110
|
+
新建一个虚拟环境,建议使用 Python 3.11.9 。
|
|
111
|
+
|
|
112
|
+
安装依赖
|
|
113
|
+
|
|
114
|
+
```shell
|
|
115
|
+
pip install -r requirements.txt
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
在项目根目录(与pyproject.toml同一路径)执行以下命令安装本插件
|
|
119
|
+
|
|
120
|
+
```shell
|
|
121
|
+
pip install -e .
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
执行 `pytest --help` 检查返回的内容是否包含以下文本,如果有的话就说明安装成功了
|
|
125
|
+
|
|
126
|
+
```
|
|
127
|
+
usage: pytest [options] [file_or_dir] [file_or_dir] [...]
|
|
128
|
+
|
|
129
|
+
positional arguments:
|
|
130
|
+
file_or_dir
|
|
131
|
+
|
|
132
|
+
general:
|
|
133
|
+
|
|
134
|
+
..... 省略中间
|
|
135
|
+
|
|
136
|
+
自动化平台插件:
|
|
137
|
+
--case_ids=CASE_IDS 要执行的测试用例ID列表,使用逗号分隔,例如:19936,19930
|
|
138
|
+
--case_ids_file=CASE_IDS_FILE
|
|
139
|
+
包含测试用例ID的文件路径,文件中每行一个ID
|
|
140
|
+
--scan 扫描模式:快速生成 Allure 报告而不实际执行测试
|
|
141
|
+
|
|
142
|
+
[pytest] ini-options in the first pytest.ini|tox.ini|setup.cfg|pyproject.toml file found:
|
|
143
|
+
|
|
144
|
+
..... 省略中间
|
|
145
|
+
|
|
146
|
+
platform_ip (string): 自动化平台IP
|
|
147
|
+
platform_port (string):
|
|
148
|
+
自动化平台端口
|
|
149
|
+
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
### 创建测试用例
|
|
153
|
+
|
|
154
|
+
在项目根目录新建 tests 目录,然后在 tests 目录中新建以 test_ 开头的 py 文件,作为测试用例。
|
|
155
|
+
|
|
156
|
+
例如新建 `test_aaa.py`,在文件中写入以下内容
|
|
157
|
+
|
|
158
|
+
```python
|
|
159
|
+
import allure
|
|
160
|
+
|
|
161
|
+
|
|
162
|
+
class TestAbc:
|
|
163
|
+
@allure.title('19936-用例1')
|
|
164
|
+
def test_abc(self):
|
|
165
|
+
print('test_abc 用例执行中')
|
|
166
|
+
|
|
167
|
+
# @pytest.mark.xfail(reason='跳过')
|
|
168
|
+
class TestAbd:
|
|
169
|
+
@allure.title('19930-用例2')
|
|
170
|
+
def test_abd(self):
|
|
171
|
+
with allure.step('步骤1'):
|
|
172
|
+
pass
|
|
173
|
+
|
|
174
|
+
# @pytest.mark.xfail(reason='跳过')
|
|
175
|
+
class TestAbe:
|
|
176
|
+
@allure.title('19932-用例3')
|
|
177
|
+
def test_abe(self):
|
|
178
|
+
pass
|
|
179
|
+
# raise AssertionError()
|
|
180
|
+
# pytest.fail('用例失败')
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
### 配置执行入口
|
|
184
|
+
|
|
185
|
+
然后再项目根目录新建 main.py 作为执行的入口,写入以下内容。
|
|
186
|
+
|
|
187
|
+
```python
|
|
188
|
+
import pytest
|
|
189
|
+
import os
|
|
190
|
+
import shutil
|
|
191
|
+
|
|
192
|
+
if __name__ == '__main__':
|
|
193
|
+
pytest_options = [
|
|
194
|
+
'tests/',
|
|
195
|
+
# '--case_ids', '456456',
|
|
196
|
+
# '--scan',
|
|
197
|
+
'-v',
|
|
198
|
+
'--alluredir', 'allure-results']
|
|
199
|
+
# shutil.rmtree('allure-results') # 如果需要清空 allure-results 目录就解除本行注释
|
|
200
|
+
pytest.main(pytest_options)
|
|
201
|
+
os.system('allure generate allure-results -o ./report --clean')
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
通过为 main.py 中的 pytest_options 列表,添加 `--case_ids` 参数可以排除指定的用例,添加或删除 `--scan` 参数可以启用或禁用扫描模式。
|
|
205
|
+
|
|
206
|
+
> 注意:如果发现 pytest_runtest_logreport 中的逻辑没有被执行。那可能是没有用例被选中(也就是本次没有执行任何用例)
|
|
207
|
+
|
|
208
|
+
修改 `plugin.py` 的话不用重新 `pip install` 安装本插件,它是实时生效的。因为 `pip install -e` 的本质是在 Python 解释器的 `site-packages` 里面做了一个软链接到了本项目。
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "pytest_platform_adapter"
|
|
7
|
+
version = "1.0.0"
|
|
8
|
+
dependencies = [
|
|
9
|
+
"pytest>=6.2.5",
|
|
10
|
+
"allure-pytest>=2.9.45"
|
|
11
|
+
]
|
|
12
|
+
requires-python = ">=3.6"
|
|
13
|
+
authors = [
|
|
14
|
+
{ name = "BlackYau", email = "blackyau426@gmail.com" }
|
|
15
|
+
]
|
|
16
|
+
maintainers = [
|
|
17
|
+
{ name = "BlackYau", email = "blackyau426@gmail.com" }
|
|
18
|
+
]
|
|
19
|
+
description = "Pytest集成自动化平台插件"
|
|
20
|
+
readme = "README.md"
|
|
21
|
+
license = { text = "MIT" }
|
|
22
|
+
keywords = ["pytest", "platform", "adapter", "自动化平台", "插件"]
|
|
23
|
+
classifiers = [
|
|
24
|
+
'Development Status :: 5 - Production/Stable',
|
|
25
|
+
'Environment :: Plugins',
|
|
26
|
+
'Framework :: Pytest',
|
|
27
|
+
'Intended Audience :: Developers',
|
|
28
|
+
'License :: OSI Approved :: MIT License',
|
|
29
|
+
'Natural Language :: Chinese (Simplified)',
|
|
30
|
+
'Programming Language :: Python :: 3',
|
|
31
|
+
'Programming Language :: Python :: 3.6',
|
|
32
|
+
'Programming Language :: Python :: 3.7',
|
|
33
|
+
'Programming Language :: Python :: 3.8',
|
|
34
|
+
'Programming Language :: Python :: 3.9',
|
|
35
|
+
'Programming Language :: Python :: 3.10',
|
|
36
|
+
'Programming Language :: Python :: 3.11',
|
|
37
|
+
'Topic :: Software Development',
|
|
38
|
+
'Topic :: Software Development :: Testing',
|
|
39
|
+
'Topic :: Software Development :: Testing :: Acceptance',
|
|
40
|
+
'Topic :: Software Development :: Libraries',
|
|
41
|
+
'Topic :: Software Development :: Libraries :: Python Modules'
|
|
42
|
+
]
|
|
43
|
+
|
|
44
|
+
[project.urls]
|
|
45
|
+
Homepage = "https://github.com/blackyau/pytest-platform-adapter"
|
|
46
|
+
Repository = "https://github.com/blackyau/pytest-platform-adapter.git"
|
|
47
|
+
Issues = "https://github.com/blackyau/pytest-platform-adapter/issues"
|
|
48
|
+
|
|
49
|
+
[project.entry-points.pytest11]
|
|
50
|
+
platform-adapter = "pytest_platform_adapter.plugin"
|
|
File without changes
|
|
@@ -0,0 +1,265 @@
|
|
|
1
|
+
import asyncio
|
|
2
|
+
import json
|
|
3
|
+
import os
|
|
4
|
+
from typing import List, Optional
|
|
5
|
+
|
|
6
|
+
import requests
|
|
7
|
+
from allure_pytest.utils import allure_title
|
|
8
|
+
import logging
|
|
9
|
+
import pytest
|
|
10
|
+
|
|
11
|
+
logger = logging.getLogger('pytest-platform-adapter')
|
|
12
|
+
logger.setLevel(logging.INFO)
|
|
13
|
+
|
|
14
|
+
# 全局变量用于统计测试用例状态
|
|
15
|
+
test_stats = {
|
|
16
|
+
'total': 0,
|
|
17
|
+
'passed': 0,
|
|
18
|
+
'failed': 0,
|
|
19
|
+
'skipped': 0,
|
|
20
|
+
'current': 0 # 当前已执行的用例数
|
|
21
|
+
}
|
|
22
|
+
milestone_counter = 10 # 里程碑计数器
|
|
23
|
+
failed_cases = set() # 记录已标记为失败的用例
|
|
24
|
+
skipped_cases = set() # 记录已标记为跳过的用例
|
|
25
|
+
cases_ids = set() # 存放所有用例ID,用来检查是否有重复的
|
|
26
|
+
scan_enable = False # 记录是否扫描模式,默认为False非扫描模式,True为扫描模式
|
|
27
|
+
platform_ip = None
|
|
28
|
+
platform_port = None
|
|
29
|
+
platform_path = None
|
|
30
|
+
pipeline_name = None
|
|
31
|
+
build_number = None
|
|
32
|
+
platform_use_https = False
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def pytest_addoption(parser):
|
|
36
|
+
group = parser.getgroup('platform-adapter', '自动化平台插件')
|
|
37
|
+
group.addoption(
|
|
38
|
+
'--case_ids',
|
|
39
|
+
action='store',
|
|
40
|
+
default=None,
|
|
41
|
+
help='要执行的测试用例ID列表,使用逗号分隔,例如:19936,19930'
|
|
42
|
+
)
|
|
43
|
+
group.addoption(
|
|
44
|
+
'--case_ids_file',
|
|
45
|
+
action='store',
|
|
46
|
+
default=None,
|
|
47
|
+
help='包含测试用例ID的文件路径,文件中每行一个ID'
|
|
48
|
+
)
|
|
49
|
+
group.addoption(
|
|
50
|
+
'--scan',
|
|
51
|
+
action='store_true',
|
|
52
|
+
default=False,
|
|
53
|
+
help='扫描模式:快速生成 Allure 报告而不实际执行测试'
|
|
54
|
+
)
|
|
55
|
+
parser.addini(
|
|
56
|
+
'platform_ip',
|
|
57
|
+
help='自动化平台API IP',
|
|
58
|
+
default=None
|
|
59
|
+
)
|
|
60
|
+
parser.addini(
|
|
61
|
+
'platform_port',
|
|
62
|
+
help='自动化平台API端口',
|
|
63
|
+
default=None
|
|
64
|
+
)
|
|
65
|
+
parser.addini(
|
|
66
|
+
'platform_path',
|
|
67
|
+
help='自动化平台API Path',
|
|
68
|
+
default='/api/autoplatform/task/refresh_data_count'
|
|
69
|
+
)
|
|
70
|
+
parser.addini(
|
|
71
|
+
'platform_use_https',
|
|
72
|
+
help='上报自动化平台时启用HTTPS,默认不启用',
|
|
73
|
+
default=False
|
|
74
|
+
)
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
def pytest_collection_modifyitems(config, items):
|
|
78
|
+
"""
|
|
79
|
+
hook收集用例的过程,给--case_ids和--case_ids_file提供支持
|
|
80
|
+
修改测试用例集合,根据提供的测试用例ID过滤测试用例
|
|
81
|
+
"""
|
|
82
|
+
target_ids = get_target_test_ids(config)
|
|
83
|
+
if not target_ids:
|
|
84
|
+
test_stats['total'] = len(items) # 更新总用例数
|
|
85
|
+
return
|
|
86
|
+
selected = []
|
|
87
|
+
deselected = []
|
|
88
|
+
for item in items:
|
|
89
|
+
title = allure_title(item)
|
|
90
|
+
test_id = get_test_id_from_title(title)
|
|
91
|
+
if test_id in target_ids:
|
|
92
|
+
selected.append(item)
|
|
93
|
+
else:
|
|
94
|
+
deselected.append(item)
|
|
95
|
+
# 检测 ID 是否有重复,只是单纯的检查一下,不影响执行
|
|
96
|
+
if test_id in cases_ids:
|
|
97
|
+
# 为 None 在这里就不用打印log了,因为在 get_test_id_from_title 里面就会报错一次
|
|
98
|
+
if test_id is None:
|
|
99
|
+
continue
|
|
100
|
+
logger.warning(f"测试用例ID {test_id} 重复")
|
|
101
|
+
else:
|
|
102
|
+
cases_ids.add(test_id)
|
|
103
|
+
if deselected:
|
|
104
|
+
config.hook.pytest_deselected(items=deselected)
|
|
105
|
+
items[:] = selected
|
|
106
|
+
selected_ids = [get_test_id_from_title(allure_title(item)) for item in selected]
|
|
107
|
+
test_stats['total'] = len(selected) # 更新总用例数
|
|
108
|
+
logger.info("目标测试用例ID (%d个): %s", len(target_ids), target_ids)
|
|
109
|
+
logger.info("实际执行用例ID (%d个): %s", len(selected_ids), selected_ids)
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
@pytest.hookimpl(hookwrapper=True)
|
|
113
|
+
def pytest_runtest_call(item):
|
|
114
|
+
if item.config.getoption('--scan'):
|
|
115
|
+
# logger.info(f"扫描模式:跳过执行测试用例 {allure_title(item)}")
|
|
116
|
+
pytest.skip("扫描模式已启动,跳过执行测试用例")
|
|
117
|
+
yield
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
@pytest.hookimpl(hookwrapper=True)
|
|
121
|
+
def pytest_runtest_setup(item):
|
|
122
|
+
if item.config.getoption('--scan'):
|
|
123
|
+
# logger.info(f"扫描模式:跳过测试用例 {allure_title(item)}前置")
|
|
124
|
+
pytest.skip("扫描模式已启动,跳过测试用例前置")
|
|
125
|
+
yield
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
@pytest.hookimpl(hookwrapper=True)
|
|
129
|
+
def pytest_runtest_teardown(item):
|
|
130
|
+
if item.config.getoption('--scan'):
|
|
131
|
+
# logger.info(f"扫描模式:跳过测试用例 {allure_title(item)}后置")
|
|
132
|
+
pytest.skip("扫描模式已启动,跳过测试用例后置")
|
|
133
|
+
yield
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
@pytest.hookimpl
|
|
137
|
+
def pytest_runtest_logreport(report):
|
|
138
|
+
"""
|
|
139
|
+
hook测试用例执行结果的输出过程
|
|
140
|
+
"""
|
|
141
|
+
global milestone_counter, scan_enable, platform_ip, platform_port, platform_path, platform_use_https
|
|
142
|
+
global pipeline_name, build_number
|
|
143
|
+
# config = pytest.Config
|
|
144
|
+
# my_option = config.getini("my_option")
|
|
145
|
+
# 使用 report.nodeid 作为唯一标识
|
|
146
|
+
nodeid = report.nodeid
|
|
147
|
+
|
|
148
|
+
if report.when in ['setup', 'call', 'teardown']:
|
|
149
|
+
# 记录失败状态,如果该用例任意阶段失败,则添加到 failed_cases
|
|
150
|
+
if report.failed:
|
|
151
|
+
failed_cases.add(nodeid)
|
|
152
|
+
|
|
153
|
+
# 记录跳过状态,仅在 setup 阶段处理
|
|
154
|
+
if report.skipped and report.when == 'setup':
|
|
155
|
+
skipped_cases.add(nodeid)
|
|
156
|
+
test_stats['skipped'] += 1
|
|
157
|
+
|
|
158
|
+
# 仅在 teardown 阶段完成统计更新
|
|
159
|
+
if report.when == 'teardown':
|
|
160
|
+
test_stats['current'] += 1
|
|
161
|
+
# 检查用例是否为失败、跳过或通过
|
|
162
|
+
if nodeid in failed_cases:
|
|
163
|
+
# TODO Xfail 应该计算为失败,但是不太对
|
|
164
|
+
test_stats['failed'] += 1
|
|
165
|
+
elif nodeid in skipped_cases:
|
|
166
|
+
# 如果用例已跳过,不计为通过
|
|
167
|
+
pass
|
|
168
|
+
else:
|
|
169
|
+
test_stats['passed'] += 1
|
|
170
|
+
|
|
171
|
+
# 打印进度和统计信息
|
|
172
|
+
progress = (test_stats['current'] / test_stats['total']) * 100 if test_stats['total'] != 0 else 0
|
|
173
|
+
pass_rate = (test_stats['passed'] / (test_stats['total'] - test_stats['skipped'])) * 100 if (
|
|
174
|
+
(test_stats['total'] - test_stats['skipped']) != 0) else 0
|
|
175
|
+
logger.info(
|
|
176
|
+
f"pipeline_name:{pipeline_name}, build_number: {build_number}"
|
|
177
|
+
f"用例进度: 总数 {test_stats['total']}, 跳过 {test_stats['skipped']}, 已执行 {test_stats['current']}, "
|
|
178
|
+
f"失败 {test_stats['failed']}, 通过 {test_stats['passed']}, 进度 {progress:.2f}%, 通过率 {pass_rate:.2f}%"
|
|
179
|
+
)
|
|
180
|
+
|
|
181
|
+
# 当没有启用扫描模式、同时配置了平台的IP和端口的时候才回报给自动化平台
|
|
182
|
+
if not scan_enable and platform_ip and platform_port:
|
|
183
|
+
# 在执行前10个用例的时候,进度立即回报给平台进度。之后就是每隔10个用例再回报一次
|
|
184
|
+
if test_stats['current'] <= 10 or test_stats['current'] % 10 == 0:
|
|
185
|
+
json_data = None
|
|
186
|
+
url = f"http://{platform_ip}:{platform_port}{platform_path}" if not platform_use_https \
|
|
187
|
+
else f"https://{platform_ip}:{platform_port}{platform_path}"
|
|
188
|
+
try:
|
|
189
|
+
json_data = {
|
|
190
|
+
'pipeline': pipeline_name,
|
|
191
|
+
'build_number': build_number,
|
|
192
|
+
'passed_case_count': test_stats['passed'],
|
|
193
|
+
'skipped_case_count': test_stats['skipped'],
|
|
194
|
+
'failed_case_count': test_stats['failed'],
|
|
195
|
+
'selected_case': test_stats['total'] }
|
|
196
|
+
headers = {'Content-Type': 'application/json'}
|
|
197
|
+
response = requests.post(url, data=json.dumps(json_data), headers=headers, timeout=3)
|
|
198
|
+
logger.info(f"已将数据回报给 {url},"
|
|
199
|
+
f"平台返回状态码:{response.status_code},"
|
|
200
|
+
f"响应体:{response.text},请求体:{json_data}")
|
|
201
|
+
except Exception as e:
|
|
202
|
+
logger.info(f"将请求发送到 {url}"
|
|
203
|
+
f",请求体:{json_data} 错误信息:{e}")
|
|
204
|
+
|
|
205
|
+
|
|
206
|
+
def pytest_configure(config):
|
|
207
|
+
global scan_enable, platform_ip, platform_port, platform_path
|
|
208
|
+
global pipeline_name, build_number
|
|
209
|
+
scan_enable, platform_ip, platform_port, platform_path, platform_use_https = config.getoption(
|
|
210
|
+
'--scan'), config.getini('platform_ip'), config.getini('platform_port'), config.getini(
|
|
211
|
+
'platform_path'), config.getini('platform_use_https')
|
|
212
|
+
pipeline_name = os.environ.get("JOB_NAME")
|
|
213
|
+
build_number = os.environ.get("BUILD_NUMBER")
|
|
214
|
+
handler = logging.StreamHandler()
|
|
215
|
+
handler.setLevel(logging.INFO)
|
|
216
|
+
formatter = logging.Formatter('自动化平台插件 - %(message)s')
|
|
217
|
+
handler.setFormatter(formatter)
|
|
218
|
+
logger.addHandler(handler)
|
|
219
|
+
config.addinivalue_line(
|
|
220
|
+
"markers",
|
|
221
|
+
"allure_title: 使用allure标题标记测试用例"
|
|
222
|
+
)
|
|
223
|
+
|
|
224
|
+
|
|
225
|
+
def get_test_ids_from_file(file_path: str) -> List[str]:
|
|
226
|
+
with open(file_path, 'r') as f:
|
|
227
|
+
return [line.strip() for line in f if line.strip()]
|
|
228
|
+
|
|
229
|
+
|
|
230
|
+
def get_test_ids_from_option(ids_string: str) -> List[str]:
|
|
231
|
+
case_id = []
|
|
232
|
+
for id_ in ids_string.strip(',').split(','):
|
|
233
|
+
id_strip = id_.strip()
|
|
234
|
+
if not id_strip.isdigit():
|
|
235
|
+
logger.error(f'存在无效的测试用例ID:{id_}')
|
|
236
|
+
continue
|
|
237
|
+
else:
|
|
238
|
+
case_id.append(id_strip)
|
|
239
|
+
return case_id
|
|
240
|
+
|
|
241
|
+
|
|
242
|
+
def get_target_test_ids(config) -> Optional[List[str]]:
|
|
243
|
+
case_ids = config.getoption('--case_ids')
|
|
244
|
+
case_ids_file = config.getoption('--case_ids_file')
|
|
245
|
+
if case_ids:
|
|
246
|
+
logger.info(f"接收到case_ids入参为:'{case_ids}'")
|
|
247
|
+
return get_test_ids_from_option(case_ids)
|
|
248
|
+
elif case_ids_file:
|
|
249
|
+
logger.info(f"接收到case_ids_file入参为:'{case_ids_file}'")
|
|
250
|
+
return get_test_ids_from_file(case_ids_file)
|
|
251
|
+
return None
|
|
252
|
+
|
|
253
|
+
|
|
254
|
+
def get_test_id_from_title(title: Optional[str]) -> Optional[str]:
|
|
255
|
+
if not title:
|
|
256
|
+
return None
|
|
257
|
+
match = title.split('-', 1)
|
|
258
|
+
if len(match) != 2:
|
|
259
|
+
logger.error(f'存在无法解析用例ID的用例,用例标题为:{title}')
|
|
260
|
+
return None
|
|
261
|
+
if match[0].isdigit():
|
|
262
|
+
return match[0]
|
|
263
|
+
else:
|
|
264
|
+
logger.error(f'存在无法解析用例ID的用例,用例标题为:{title}')
|
|
265
|
+
return None
|
|
@@ -0,0 +1,243 @@
|
|
|
1
|
+
Metadata-Version: 2.2
|
|
2
|
+
Name: pytest_platform_adapter
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: Pytest集成自动化平台插件
|
|
5
|
+
Author-email: BlackYau <blackyau426@gmail.com>
|
|
6
|
+
Maintainer-email: BlackYau <blackyau426@gmail.com>
|
|
7
|
+
License: MIT
|
|
8
|
+
Project-URL: Homepage, https://github.com/blackyau/pytest-platform-adapter
|
|
9
|
+
Project-URL: Repository, https://github.com/blackyau/pytest-platform-adapter.git
|
|
10
|
+
Project-URL: Issues, https://github.com/blackyau/pytest-platform-adapter/issues
|
|
11
|
+
Keywords: pytest,platform,adapter,自动化平台,插件
|
|
12
|
+
Classifier: Development Status :: 5 - Production/Stable
|
|
13
|
+
Classifier: Environment :: Plugins
|
|
14
|
+
Classifier: Framework :: Pytest
|
|
15
|
+
Classifier: Intended Audience :: Developers
|
|
16
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
17
|
+
Classifier: Natural Language :: Chinese (Simplified)
|
|
18
|
+
Classifier: Programming Language :: Python :: 3
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.6
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.7
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.8
|
|
22
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
23
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
24
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
25
|
+
Classifier: Topic :: Software Development
|
|
26
|
+
Classifier: Topic :: Software Development :: Testing
|
|
27
|
+
Classifier: Topic :: Software Development :: Testing :: Acceptance
|
|
28
|
+
Classifier: Topic :: Software Development :: Libraries
|
|
29
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
30
|
+
Requires-Python: >=3.6
|
|
31
|
+
Description-Content-Type: text/markdown
|
|
32
|
+
License-File: LICENSE
|
|
33
|
+
Requires-Dist: pytest>=6.2.5
|
|
34
|
+
Requires-Dist: allure-pytest>=2.9.45
|
|
35
|
+
|
|
36
|
+
# pytest-platform-adapter
|
|
37
|
+
|
|
38
|
+
[](https://pypi.python.org/pypi/pytest-platform-adapter)
|
|
40
|
+
[](https://pypi.python.org/pypi/pytest-platform-adapter)
|
|
41
|
+
[](https://github.com/allure-framework/allure-python/actions/workflows/build.yaml)
|
|
42
|
+
|
|
43
|
+
Pytest集成自动化平台插件
|
|
44
|
+
|
|
45
|
+
## 功能
|
|
46
|
+
|
|
47
|
+
- 根据用例 `allure.title` 中的 ID 筛选执行的用例
|
|
48
|
+
- 跳过所有用例的执行,快速生成 Allure 报告
|
|
49
|
+
- 周期性的通过 RESTApi 上报执行用例的整体进度
|
|
50
|
+
|
|
51
|
+
## 环境依赖
|
|
52
|
+
|
|
53
|
+
- Python >= 3.6
|
|
54
|
+
- pytest >= 7.1.2
|
|
55
|
+
- allure-pytest >= 2.9.45
|
|
56
|
+
|
|
57
|
+
## 安装
|
|
58
|
+
|
|
59
|
+
执行以下命令即可完成安装
|
|
60
|
+
|
|
61
|
+
```shell
|
|
62
|
+
pip install pytest-platform-adapter
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
## 使用方法
|
|
66
|
+
|
|
67
|
+
### 根据 Allure title 中的 ID 筛选用例
|
|
68
|
+
|
|
69
|
+
假设有以下测试用例
|
|
70
|
+
|
|
71
|
+
```python
|
|
72
|
+
import allure
|
|
73
|
+
|
|
74
|
+
@allure.title('19936-测试用例1')
|
|
75
|
+
def test_case1():
|
|
76
|
+
assert True
|
|
77
|
+
|
|
78
|
+
@allure.title('19930-测试用例2')
|
|
79
|
+
def test_case2():
|
|
80
|
+
assert True
|
|
81
|
+
|
|
82
|
+
@allure.title('19939-测试用例3')
|
|
83
|
+
def test_case3():
|
|
84
|
+
assert True
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
该插件提供两种方式来筛选测试用例:
|
|
88
|
+
|
|
89
|
+
1. 通过命令行参数指定测试ID:
|
|
90
|
+
```bash
|
|
91
|
+
pytest tests/ -v --case-ids="19936,19930"
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
2. 通过文件指定测试ID:
|
|
95
|
+
```bash
|
|
96
|
+
pytest tests/ -v --case-ids-file="test_ids.txt"
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
其中 test_ids.txt 的内容格式如下:
|
|
100
|
+
```
|
|
101
|
+
19936
|
|
102
|
+
19930
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
### 跳过所有用例
|
|
106
|
+
|
|
107
|
+
使用 `--scan` 参数,启用扫描模式。在扫描模式下,所有用例都会被 skip 不会执行,可以用于快速生成 Allure 报告。使用方法如下:
|
|
108
|
+
|
|
109
|
+
```shell
|
|
110
|
+
pytest --scan --alluredir allure-results
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
### 将执行进展通过RESTApi回报
|
|
114
|
+
|
|
115
|
+
在 pytest.ini 中配置以下内容
|
|
116
|
+
|
|
117
|
+
```ini
|
|
118
|
+
[pytest]
|
|
119
|
+
platform_ip = 127.0.0.1
|
|
120
|
+
platform_port = 8080
|
|
121
|
+
platform_path = /api/autoplatform/task/refresh_data_count
|
|
122
|
+
platform_use_https = False
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
执行用例的过程中(前 10 个用例的时候执行完就立刻回报,之后就是每隔 10 个用例才回报一次) 会将测试用例的整体进展以 `POST` 的方式回报给 `http://127.0.0.1:8080/api/autoplatform/task/refresh_data_count` 请求体如下:
|
|
126
|
+
|
|
127
|
+
```json
|
|
128
|
+
{
|
|
129
|
+
"pipeline": "JOB_NAME",
|
|
130
|
+
"build_number": "BUILD_NUMBER",
|
|
131
|
+
"passed_case_count": 29,
|
|
132
|
+
"skipped_case_count": 1,
|
|
133
|
+
"failed_case_count": 0,
|
|
134
|
+
"selected_case": 100
|
|
135
|
+
}
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
其中 `JOB_NAME` 和 `BUILD_NUMBER` 是通过环境变量获取的。
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
## 调试方法
|
|
142
|
+
|
|
143
|
+
### 部署虚拟环境
|
|
144
|
+
|
|
145
|
+
新建一个虚拟环境,建议使用 Python 3.11.9 。
|
|
146
|
+
|
|
147
|
+
安装依赖
|
|
148
|
+
|
|
149
|
+
```shell
|
|
150
|
+
pip install -r requirements.txt
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
在项目根目录(与pyproject.toml同一路径)执行以下命令安装本插件
|
|
154
|
+
|
|
155
|
+
```shell
|
|
156
|
+
pip install -e .
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
执行 `pytest --help` 检查返回的内容是否包含以下文本,如果有的话就说明安装成功了
|
|
160
|
+
|
|
161
|
+
```
|
|
162
|
+
usage: pytest [options] [file_or_dir] [file_or_dir] [...]
|
|
163
|
+
|
|
164
|
+
positional arguments:
|
|
165
|
+
file_or_dir
|
|
166
|
+
|
|
167
|
+
general:
|
|
168
|
+
|
|
169
|
+
..... 省略中间
|
|
170
|
+
|
|
171
|
+
自动化平台插件:
|
|
172
|
+
--case_ids=CASE_IDS 要执行的测试用例ID列表,使用逗号分隔,例如:19936,19930
|
|
173
|
+
--case_ids_file=CASE_IDS_FILE
|
|
174
|
+
包含测试用例ID的文件路径,文件中每行一个ID
|
|
175
|
+
--scan 扫描模式:快速生成 Allure 报告而不实际执行测试
|
|
176
|
+
|
|
177
|
+
[pytest] ini-options in the first pytest.ini|tox.ini|setup.cfg|pyproject.toml file found:
|
|
178
|
+
|
|
179
|
+
..... 省略中间
|
|
180
|
+
|
|
181
|
+
platform_ip (string): 自动化平台IP
|
|
182
|
+
platform_port (string):
|
|
183
|
+
自动化平台端口
|
|
184
|
+
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
### 创建测试用例
|
|
188
|
+
|
|
189
|
+
在项目根目录新建 tests 目录,然后在 tests 目录中新建以 test_ 开头的 py 文件,作为测试用例。
|
|
190
|
+
|
|
191
|
+
例如新建 `test_aaa.py`,在文件中写入以下内容
|
|
192
|
+
|
|
193
|
+
```python
|
|
194
|
+
import allure
|
|
195
|
+
|
|
196
|
+
|
|
197
|
+
class TestAbc:
|
|
198
|
+
@allure.title('19936-用例1')
|
|
199
|
+
def test_abc(self):
|
|
200
|
+
print('test_abc 用例执行中')
|
|
201
|
+
|
|
202
|
+
# @pytest.mark.xfail(reason='跳过')
|
|
203
|
+
class TestAbd:
|
|
204
|
+
@allure.title('19930-用例2')
|
|
205
|
+
def test_abd(self):
|
|
206
|
+
with allure.step('步骤1'):
|
|
207
|
+
pass
|
|
208
|
+
|
|
209
|
+
# @pytest.mark.xfail(reason='跳过')
|
|
210
|
+
class TestAbe:
|
|
211
|
+
@allure.title('19932-用例3')
|
|
212
|
+
def test_abe(self):
|
|
213
|
+
pass
|
|
214
|
+
# raise AssertionError()
|
|
215
|
+
# pytest.fail('用例失败')
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
### 配置执行入口
|
|
219
|
+
|
|
220
|
+
然后再项目根目录新建 main.py 作为执行的入口,写入以下内容。
|
|
221
|
+
|
|
222
|
+
```python
|
|
223
|
+
import pytest
|
|
224
|
+
import os
|
|
225
|
+
import shutil
|
|
226
|
+
|
|
227
|
+
if __name__ == '__main__':
|
|
228
|
+
pytest_options = [
|
|
229
|
+
'tests/',
|
|
230
|
+
# '--case_ids', '456456',
|
|
231
|
+
# '--scan',
|
|
232
|
+
'-v',
|
|
233
|
+
'--alluredir', 'allure-results']
|
|
234
|
+
# shutil.rmtree('allure-results') # 如果需要清空 allure-results 目录就解除本行注释
|
|
235
|
+
pytest.main(pytest_options)
|
|
236
|
+
os.system('allure generate allure-results -o ./report --clean')
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
通过为 main.py 中的 pytest_options 列表,添加 `--case_ids` 参数可以排除指定的用例,添加或删除 `--scan` 参数可以启用或禁用扫描模式。
|
|
240
|
+
|
|
241
|
+
> 注意:如果发现 pytest_runtest_logreport 中的逻辑没有被执行。那可能是没有用例被选中(也就是本次没有执行任何用例)
|
|
242
|
+
|
|
243
|
+
修改 `plugin.py` 的话不用重新 `pip install` 安装本插件,它是实时生效的。因为 `pip install -e` 的本质是在 Python 解释器的 `site-packages` 里面做了一个软链接到了本项目。
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
LICENSE
|
|
2
|
+
README.md
|
|
3
|
+
pyproject.toml
|
|
4
|
+
src/pytest_platform_adapter/__init__.py
|
|
5
|
+
src/pytest_platform_adapter/plugin.py
|
|
6
|
+
src/pytest_platform_adapter.egg-info/PKG-INFO
|
|
7
|
+
src/pytest_platform_adapter.egg-info/SOURCES.txt
|
|
8
|
+
src/pytest_platform_adapter.egg-info/dependency_links.txt
|
|
9
|
+
src/pytest_platform_adapter.egg-info/entry_points.txt
|
|
10
|
+
src/pytest_platform_adapter.egg-info/requires.txt
|
|
11
|
+
src/pytest_platform_adapter.egg-info/top_level.txt
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
pytest_platform_adapter
|