addproject
This commit is contained in:
190
zhyy/test_case/JENKINS_SETUP.md
Normal file
190
zhyy/test_case/JENKINS_SETUP.md
Normal file
@@ -0,0 +1,190 @@
|
||||
# Jenkins + Allure 报告集成配置指南
|
||||
|
||||
## 前置要求
|
||||
|
||||
1. **Jenkins已安装并运行**
|
||||
2. **安装Allure插件**
|
||||
- 进入 Jenkins → Manage Jenkins → Manage Plugins
|
||||
- 搜索并安装 "Allure Plugin"
|
||||
3. **安装Allure命令行工具**
|
||||
- 下载:https://github.com/allure-framework/allure2/releases
|
||||
- 解压并添加到系统PATH环境变量
|
||||
- 或在Jenkins全局工具配置中配置Allure路径
|
||||
|
||||
## Jenkins配置步骤
|
||||
|
||||
### 方式一:使用Jenkinsfile(推荐)
|
||||
|
||||
1. **在Jenkins中创建Pipeline任务**
|
||||
- 新建任务 → 选择 "Pipeline"
|
||||
- 任务名称:例如 "ZZYY_Test_Automation"
|
||||
|
||||
2. **配置Pipeline**
|
||||
- Pipeline definition → Pipeline script from SCM
|
||||
- SCM: Git(或其他版本控制)
|
||||
- Script Path: `zhyy/test_case/Jenkinsfile`
|
||||
- 保存
|
||||
|
||||
3. **运行任务**
|
||||
- 点击 "Build with Parameters"
|
||||
- 选择运行方式(RUN_TYPE)
|
||||
- 填写相应参数
|
||||
- 点击 "Build"
|
||||
|
||||
### 方式二:自由风格项目配置
|
||||
|
||||
1. **创建自由风格项目**
|
||||
- 新建任务 → 选择 "Freestyle project"
|
||||
- 任务名称:例如 "ZZYY_Test_Automation"
|
||||
|
||||
2. **配置源码管理**
|
||||
- Source Code Management → Git
|
||||
- Repository URL: 你的Git仓库地址
|
||||
- Branch: 分支名称
|
||||
|
||||
3. **配置构建步骤**
|
||||
- Build → Add build step → Execute shell(Linux/Mac)或 Execute Windows batch command(Windows)
|
||||
- 命令示例:
|
||||
```bash
|
||||
# Linux/Mac
|
||||
cd ${WORKSPACE}
|
||||
python zhyy/test_case/run_tests.py --all --no-report
|
||||
```
|
||||
```batch
|
||||
# Windows
|
||||
cd %WORKSPACE%
|
||||
python zhyy\test_case\run_tests.py --all --no-report
|
||||
```
|
||||
|
||||
4. **配置Allure报告**
|
||||
- Post-build Actions → Add post-build action → Allure Report
|
||||
- Results path: `zhyy/test_case/reports/allure-results`
|
||||
- Report path: `zhyy/test_case/reports/allure-report`(可选)
|
||||
- 保存
|
||||
|
||||
5. **配置参数化构建(可选)**
|
||||
- This project is parameterized → Add Parameter
|
||||
- 添加Choice Parameter:
|
||||
- Name: `RUN_TYPE`
|
||||
- Choices: `all`, `feature`, `story`, `dir`, `file`, `keyword`, `marker`
|
||||
- 添加String Parameter(根据需要):
|
||||
- `FEATURE_NAME`, `STORY_NAME`, `DIR_PATH`, `FILE_PATH`, `KEYWORD`, `MARKER`
|
||||
|
||||
6. **修改构建命令以使用参数**
|
||||
```bash
|
||||
# Linux/Mac
|
||||
cd ${WORKSPACE}
|
||||
if [ "${RUN_TYPE}" = "all" ]; then
|
||||
python zhyy/test_case/run_tests.py --all --no-report
|
||||
elif [ "${RUN_TYPE}" = "feature" ]; then
|
||||
python zhyy/test_case/run_tests.py --feature "${FEATURE_NAME}" --no-report
|
||||
elif [ "${RUN_TYPE}" = "dir" ]; then
|
||||
python zhyy/test_case/run_tests.py --dir "${DIR_PATH}" --no-report
|
||||
# ... 其他条件
|
||||
fi
|
||||
```
|
||||
|
||||
## Allure插件配置
|
||||
|
||||
### 全局工具配置
|
||||
|
||||
1. **配置Allure命令行工具路径**
|
||||
- Manage Jenkins → Global Tool Configuration
|
||||
- Allure Commandline → Add Allure Commandline
|
||||
- Name: `Allure`(或自定义名称)
|
||||
- Installation directory: Allure安装路径(如:`C:\allure\bin` 或 `/usr/local/allure/bin`)
|
||||
- 保存
|
||||
|
||||
### 项目配置
|
||||
|
||||
1. **在项目配置中添加Allure报告**
|
||||
- Post-build Actions → Allure Report
|
||||
- Results path: `zhyy/test_case/reports/allure-results`
|
||||
- 勾选 "Keep allure results history"
|
||||
|
||||
## 环境变量配置
|
||||
|
||||
### Jenkins全局环境变量
|
||||
|
||||
1. **配置Python路径(如需要)**
|
||||
- Manage Jenkins → Configure System → Global properties
|
||||
- Environment variables → Add
|
||||
- Name: `PYTHONPATH`
|
||||
- Value: `${WORKSPACE}`
|
||||
|
||||
### 项目环境变量
|
||||
|
||||
在Pipeline或构建脚本中设置:
|
||||
```groovy
|
||||
environment {
|
||||
PYTHONPATH = "${WORKSPACE}"
|
||||
ALLURE_RESULTS = "${WORKSPACE}/zhyy/test_case/reports/allure-results"
|
||||
}
|
||||
```
|
||||
|
||||
## 使用示例
|
||||
|
||||
### 运行所有测试
|
||||
```bash
|
||||
python zhyy/test_case/run_tests.py --all --no-report
|
||||
```
|
||||
|
||||
### 按目录运行
|
||||
```bash
|
||||
python zhyy/test_case/run_tests.py --dir "接口/SZPurchase" --no-report
|
||||
```
|
||||
|
||||
### 按Feature标签运行
|
||||
```bash
|
||||
python zhyy/test_case/run_tests.py --feature "深圳采购工作台采购订单页面" --no-report
|
||||
```
|
||||
|
||||
## 报告查看
|
||||
|
||||
1. **在Jenkins中查看**
|
||||
- 构建完成后,在项目页面左侧菜单会出现 "Allure Report" 链接
|
||||
- 点击即可查看详细的测试报告
|
||||
|
||||
2. **报告内容**
|
||||
- 测试用例执行情况
|
||||
- 通过/失败统计
|
||||
- 执行时间
|
||||
- 测试步骤详情
|
||||
- 截图和日志(如果配置了)
|
||||
|
||||
## 常见问题
|
||||
|
||||
### 1. Allure命令未找到
|
||||
- 确保Allure已安装并添加到PATH
|
||||
- 或在Jenkins全局工具配置中指定Allure路径
|
||||
|
||||
### 2. 模块导入错误
|
||||
- 检查PYTHONPATH环境变量
|
||||
- 确保项目根目录在Python路径中
|
||||
|
||||
### 3. 报告未生成
|
||||
- 检查allure-results目录是否存在且包含数据
|
||||
- 检查Jenkins Allure插件配置的路径是否正确
|
||||
|
||||
### 4. 权限问题
|
||||
- 确保Jenkins有权限访问工作空间目录
|
||||
- 确保有权限执行Python和Allure命令
|
||||
|
||||
## 邮件通知配置(可选)
|
||||
|
||||
在Post-build Actions中添加:
|
||||
- Email Notification
|
||||
- 配置收件人、主题等
|
||||
- 可以附加Allure报告链接
|
||||
|
||||
## 定时构建(可选)
|
||||
|
||||
在项目配置中:
|
||||
- Build Triggers → Build periodically
|
||||
- 例如:`H 2 * * *`(每天凌晨2点执行)
|
||||
|
||||
## 多节点执行(可选)
|
||||
|
||||
如果有多台Jenkins节点:
|
||||
- 在Pipeline中配置 `agent { label 'your-node-label' }`
|
||||
- 或在自由风格项目中配置 "Restrict where this project can be run"
|
||||
175
zhyy/test_case/Jenkinsfile
vendored
Normal file
175
zhyy/test_case/Jenkinsfile
vendored
Normal file
@@ -0,0 +1,175 @@
|
||||
pipeline {
|
||||
agent any
|
||||
|
||||
options {
|
||||
// 保留最近10次构建
|
||||
buildDiscarder(logRotator(numToKeepStr: '10'))
|
||||
// 超时时间60分钟
|
||||
timeout(time: 60, unit: 'MINUTES')
|
||||
}
|
||||
|
||||
environment {
|
||||
// Python路径
|
||||
PYTHONPATH = "${WORKSPACE}"
|
||||
// Allure结果目录
|
||||
ALLURE_RESULTS = "${WORKSPACE}/zhyy/test_case/reports/allure-results"
|
||||
// Allure报告目录
|
||||
ALLURE_REPORT = "${WORKSPACE}/zhyy/test_case/reports/allure-report"
|
||||
}
|
||||
|
||||
stages {
|
||||
stage('Checkout') {
|
||||
steps {
|
||||
echo '检出代码...'
|
||||
checkout scm
|
||||
}
|
||||
}
|
||||
|
||||
stage('环境准备') {
|
||||
steps {
|
||||
echo '准备测试环境...'
|
||||
script {
|
||||
// 确保Python环境
|
||||
sh '''
|
||||
python --version
|
||||
pip --version
|
||||
'''
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
stage('运行测试') {
|
||||
steps {
|
||||
echo '执行测试用例...'
|
||||
script {
|
||||
// 根据参数选择运行方式
|
||||
def runType = params.RUN_TYPE ?: 'all'
|
||||
def testCommand = ''
|
||||
|
||||
switch(runType) {
|
||||
case 'all':
|
||||
testCommand = 'python zhyy/test_case/run_tests.py --all --no-report'
|
||||
break
|
||||
case 'feature':
|
||||
def feature = params.FEATURE_NAME ?: ''
|
||||
testCommand = "python zhyy/test_case/run_tests.py --feature \"${feature}\" --no-report"
|
||||
break
|
||||
case 'story':
|
||||
def story = params.STORY_NAME ?: ''
|
||||
testCommand = "python zhyy/test_case/run_tests.py --story \"${story}\" --no-report"
|
||||
break
|
||||
case 'dir':
|
||||
def dir = params.DIR_PATH ?: ''
|
||||
testCommand = "python zhyy/test_case/run_tests.py --dir \"${dir}\" --no-report"
|
||||
break
|
||||
case 'file':
|
||||
def file = params.FILE_PATH ?: ''
|
||||
testCommand = "python zhyy/test_case/run_tests.py --file \"${file}\" --no-report"
|
||||
break
|
||||
case 'keyword':
|
||||
def keyword = params.KEYWORD ?: ''
|
||||
testCommand = "python zhyy/test_case/run_tests.py --keyword \"${keyword}\" --no-report"
|
||||
break
|
||||
case 'marker':
|
||||
def marker = params.MARKER ?: ''
|
||||
testCommand = "python zhyy/test_case/run_tests.py --marker \"${marker}\" --no-report"
|
||||
break
|
||||
default:
|
||||
testCommand = 'python zhyy/test_case/run_tests.py --all --no-report'
|
||||
}
|
||||
|
||||
sh """
|
||||
cd ${WORKSPACE}
|
||||
${testCommand}
|
||||
"""
|
||||
}
|
||||
}
|
||||
post {
|
||||
always {
|
||||
// 无论成功失败都收集测试结果
|
||||
echo '收集测试结果...'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
stage('生成Allure报告') {
|
||||
steps {
|
||||
echo '生成Allure报告...'
|
||||
script {
|
||||
sh """
|
||||
cd ${WORKSPACE}
|
||||
allure generate ${ALLURE_RESULTS} -o ${ALLURE_REPORT} --clean || echo "Allure报告生成失败,但继续执行"
|
||||
"""
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
post {
|
||||
always {
|
||||
// 发布Allure报告
|
||||
allure([
|
||||
includeProperties: false,
|
||||
jdk: '',
|
||||
properties: [],
|
||||
reportBuildPolicy: 'ALWAYS',
|
||||
results: [[path: 'zhyy/test_case/reports/allure-results']]
|
||||
])
|
||||
|
||||
// 清理工作空间(可选)
|
||||
// cleanWs()
|
||||
}
|
||||
success {
|
||||
echo '✓ 测试执行成功'
|
||||
// 可以在这里添加成功通知,如发送邮件、钉钉等
|
||||
}
|
||||
failure {
|
||||
echo '✗ 测试执行失败'
|
||||
// 可以在这里添加失败通知
|
||||
}
|
||||
unstable {
|
||||
echo '⚠ 测试执行不稳定'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 参数化构建
|
||||
properties([
|
||||
parameters([
|
||||
choice(
|
||||
name: 'RUN_TYPE',
|
||||
choices: ['all', 'feature', 'story', 'dir', 'file', 'keyword', 'marker'],
|
||||
description: '选择运行方式'
|
||||
),
|
||||
string(
|
||||
name: 'FEATURE_NAME',
|
||||
defaultValue: '',
|
||||
description: 'Feature标签名称(当RUN_TYPE=feature时使用)'
|
||||
),
|
||||
string(
|
||||
name: 'STORY_NAME',
|
||||
defaultValue: '',
|
||||
description: 'Story标签名称(当RUN_TYPE=story时使用)'
|
||||
),
|
||||
string(
|
||||
name: 'DIR_PATH',
|
||||
defaultValue: '接口/SZPurchase',
|
||||
description: '测试目录路径(当RUN_TYPE=dir时使用,相对于TestCase目录)'
|
||||
),
|
||||
string(
|
||||
name: 'FILE_PATH',
|
||||
defaultValue: '接口/SZPurchase/PurchaseOrderManage.py',
|
||||
description: '测试文件路径(当RUN_TYPE=file时使用,相对于TestCase目录)'
|
||||
),
|
||||
string(
|
||||
name: 'KEYWORD',
|
||||
defaultValue: 'purchase',
|
||||
description: '关键字(当RUN_TYPE=keyword时使用)'
|
||||
),
|
||||
string(
|
||||
name: 'MARKER',
|
||||
defaultValue: 'smoke',
|
||||
description: 'Pytest标记(当RUN_TYPE=marker时使用)'
|
||||
)
|
||||
])
|
||||
])
|
||||
84
zhyy/test_case/README_JENKINS.md
Normal file
84
zhyy/test_case/README_JENKINS.md
Normal file
@@ -0,0 +1,84 @@
|
||||
# Jenkins + Allure 集成快速参考
|
||||
|
||||
## 快速开始
|
||||
|
||||
### 1. 安装Allure插件
|
||||
- Jenkins → Manage Jenkins → Manage Plugins
|
||||
- 搜索 "Allure Plugin" 并安装
|
||||
|
||||
### 2. 配置Allure工具
|
||||
- Manage Jenkins → Global Tool Configuration
|
||||
- Allure Commandline → 添加Allure安装路径
|
||||
|
||||
### 3. 创建Jenkins任务
|
||||
|
||||
#### 方式A:使用Jenkinsfile(推荐)
|
||||
1. 新建Pipeline任务
|
||||
2. Pipeline script from SCM
|
||||
3. Script Path: `zhyy/test_case/Jenkinsfile`
|
||||
4. 保存并运行
|
||||
|
||||
#### 方式B:自由风格项目
|
||||
1. 新建Freestyle project
|
||||
2. 构建步骤:执行 `jenkins_build.sh` 或 `jenkins_build.bat`
|
||||
3. Post-build Actions → Allure Report
|
||||
4. Results path: `zhyy/test_case/reports/allure-results`
|
||||
|
||||
## 参数化构建
|
||||
|
||||
在Jenkins任务中配置以下参数:
|
||||
|
||||
| 参数名 | 类型 | 说明 | 示例值 |
|
||||
|--------|------|------|--------|
|
||||
| RUN_TYPE | Choice | 运行方式 | all, feature, story, dir, file, keyword, marker |
|
||||
| FEATURE_NAME | String | Feature标签 | 深圳采购工作台采购订单页面 |
|
||||
| STORY_NAME | String | Story标签 | 验证采购工作台采购订单页面列表查询 |
|
||||
| DIR_PATH | String | 目录路径 | 接口/SZPurchase |
|
||||
| FILE_PATH | String | 文件路径 | 接口/SZPurchase/PurchaseOrderManage.py |
|
||||
| KEYWORD | String | 关键字 | purchase |
|
||||
| MARKER | String | Pytest标记 | smoke |
|
||||
|
||||
## 常用命令
|
||||
|
||||
### 本地运行
|
||||
```bash
|
||||
# 运行所有测试
|
||||
python run_tests.py
|
||||
|
||||
# 按目录运行
|
||||
python run_tests.py --dir "接口/SZPurchase"
|
||||
|
||||
# 按文件运行
|
||||
python run_tests.py --file "接口/SZPurchase/PurchaseOrderManage.py"
|
||||
|
||||
# 生成并打开报告
|
||||
python run_tests.py --all --report --open
|
||||
```
|
||||
|
||||
### Jenkins中运行
|
||||
```bash
|
||||
# 使用构建脚本(自动检测参数)
|
||||
bash jenkins_build.sh
|
||||
|
||||
# 或直接使用run_tests.py
|
||||
python run_tests.py --all --no-report
|
||||
```
|
||||
|
||||
## Allure报告路径
|
||||
|
||||
- **结果目录**: `zhyy/test_case/reports/allure-results`
|
||||
- **报告目录**: `zhyy/test_case/reports/allure-report`
|
||||
- **Jenkins中查看**: 构建完成后点击左侧 "Allure Report" 链接
|
||||
|
||||
## 环境变量
|
||||
|
||||
Jenkins会自动设置以下环境变量:
|
||||
- `WORKSPACE`: Jenkins工作空间路径
|
||||
- `BUILD_NUMBER`: 构建编号
|
||||
- `JENKINS_URL`: Jenkins服务器地址
|
||||
|
||||
`run_tests.py` 会自动检测Jenkins环境并调整路径。
|
||||
|
||||
## 详细文档
|
||||
|
||||
更多配置说明请参考:`JENKINS_SETUP.md`
|
||||
96
zhyy/test_case/README_RUN_TESTS.md
Normal file
96
zhyy/test_case/README_RUN_TESTS.md
Normal file
@@ -0,0 +1,96 @@
|
||||
# 测试执行说明
|
||||
|
||||
## 统一测试执行工具
|
||||
|
||||
使用 `run_tests.py` 可以方便地执行各种测试用例。
|
||||
|
||||
## 安装依赖
|
||||
|
||||
```bash
|
||||
pip install pytest
|
||||
pip install pytest-allure-adaptor # 或 allure-pytest
|
||||
pip install allure-python-commons
|
||||
```
|
||||
|
||||
## 使用方法
|
||||
|
||||
### 1. 运行所有测试用例
|
||||
|
||||
```bash
|
||||
python run_tests.py --all
|
||||
```
|
||||
|
||||
### 2. 按 Allure Feature 标签运行
|
||||
|
||||
```bash
|
||||
python run_tests.py --feature "深圳采购工作台采购订单页面"
|
||||
```
|
||||
|
||||
### 3. 按 Allure Story 标签运行
|
||||
|
||||
```bash
|
||||
python run_tests.py --story "验证采购工作台采购订单页面列表查询"
|
||||
```
|
||||
|
||||
### 4. 按目录运行
|
||||
|
||||
```bash
|
||||
python run_tests.py --dir "接口/SZPurchase"
|
||||
```
|
||||
|
||||
### 5. 按文件运行
|
||||
|
||||
```bash
|
||||
python run_tests.py --file "接口/SZPurchase/PurchaseOrderManage.py"
|
||||
```
|
||||
|
||||
### 6. 按关键字运行(匹配文件名或类名)
|
||||
|
||||
```bash
|
||||
python run_tests.py --keyword "purchase"
|
||||
```
|
||||
|
||||
### 7. 按 pytest 标记运行
|
||||
|
||||
```bash
|
||||
python run_tests.py --marker "smoke"
|
||||
```
|
||||
|
||||
### 8. 生成并打开 Allure 报告
|
||||
|
||||
```bash
|
||||
python run_tests.py --all --report --open
|
||||
```
|
||||
|
||||
## 快捷方式(Windows)
|
||||
|
||||
- `run_all.bat` - 运行所有测试用例
|
||||
- `run_purchase.bat` - 运行采购相关测试用例
|
||||
|
||||
## 参数说明
|
||||
|
||||
- `--all`: 运行所有测试用例
|
||||
- `--feature <name>`: 按allure feature标签运行
|
||||
- `--story <name>`: 按allure story标签运行
|
||||
- `--dir <path>`: 按目录运行(相对于TestCase目录)
|
||||
- `--file <path>`: 按文件运行(相对于TestCase目录)
|
||||
- `--keyword <keyword>`: 按关键字运行
|
||||
- `--marker <marker>`: 按pytest标记运行
|
||||
- `--report`: 生成Allure报告
|
||||
- `--open`: 打开Allure报告
|
||||
- `--no-report`: 不生成Allure报告
|
||||
|
||||
## 报告位置
|
||||
|
||||
- Allure结果: `reports/allure-results/`
|
||||
- Allure报告: `reports/allure-report/`
|
||||
|
||||
## 查看报告
|
||||
|
||||
生成报告后,可以使用以下命令打开:
|
||||
|
||||
```bash
|
||||
allure open reports/allure-report
|
||||
```
|
||||
|
||||
或者直接使用 `--open` 参数自动打开。
|
||||
9
zhyy/test_case/Resource/AdapterKws/hh-qa.robot
Normal file
9
zhyy/test_case/Resource/AdapterKws/hh-qa.robot
Normal file
@@ -0,0 +1,9 @@
|
||||
*** Settings ***
|
||||
*** Variables ***
|
||||
|
||||
${parent_phone_1} 13400234900 # 增长业务使用(陈江)(陈洁-login、留资等也在使用),逻辑思维用户
|
||||
${parentphone_customerId_1} 6022462 #用户 13400234900逻辑思维线索id
|
||||
${parent_phone_2} 12030990019 #张楠 course_package.robot(陈洁-login、留资等也在使用),中文素养用户
|
||||
${parent_phone_3} 13400234902 # 海报任务专用
|
||||
|
||||
|
||||
0
zhyy/test_case/TestCase/__init__.py
Normal file
0
zhyy/test_case/TestCase/__init__.py
Normal file
BIN
zhyy/test_case/TestCase/__pycache__/__init__.cpython-38.pyc
Normal file
BIN
zhyy/test_case/TestCase/__pycache__/__init__.cpython-38.pyc
Normal file
Binary file not shown.
Binary file not shown.
75
zhyy/test_case/TestCase/接口/SZPurchase/PurchaseOrderManage.py
Normal file
75
zhyy/test_case/TestCase/接口/SZPurchase/PurchaseOrderManage.py
Normal file
@@ -0,0 +1,75 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import allure
|
||||
import logging
|
||||
|
||||
from zhyy.library.BusinessKw.SZPurchase.PurchaseOrderManage import PurchaseOrder
|
||||
|
||||
|
||||
@allure.feature('深圳采购工作台采购订单页面')
|
||||
class Test_purchase_order(object):
|
||||
test_case = PurchaseOrder()
|
||||
|
||||
def teardown_method(self):
|
||||
logging.info("-----------------------------End-------------------------------")
|
||||
|
||||
@allure.story("验证采购工作台采购订单页面列表查询")
|
||||
def test_check_purchase_order_page(self):
|
||||
purchase_order_code = 'PO251209048' # 采购单号 必填
|
||||
supplier_company_ids = ['334'] # 供应商id 非必填
|
||||
payment_status = '0' # 付款状态 非必填
|
||||
status = '0' # 采购单状态 非必填
|
||||
page_no = 1 # 页码 必填
|
||||
page_size = 10 # 每页条数 必填
|
||||
response_data = self.test_case.kw_zhyy_get_purchase_page_post(
|
||||
note="采购工作台采购订单页面列表查询",
|
||||
user='purchase',
|
||||
order_sn=purchase_order_code,
|
||||
supplier_company_ids=supplier_company_ids,
|
||||
payment_status=payment_status,
|
||||
status=status,
|
||||
page_no=page_no,
|
||||
page_size=page_size
|
||||
)
|
||||
|
||||
# 断言检查
|
||||
assert response_data is not None, "响应数据不能为空"
|
||||
assert 'code' in response_data, "响应数据中缺少code字段"
|
||||
assert response_data['code'] == 0, "接口调用失败,code: {}, msg: {}".format(
|
||||
response_data.get('code'), response_data.get('msg', '未知错误'))
|
||||
assert 'data' in response_data, "响应数据中缺少data字段"
|
||||
assert response_data['data'] is not None, "响应数据中的data字段不能为空"
|
||||
|
||||
# 如果传入了采购单号,检查返回的数据中是否包含该采购单号
|
||||
if purchase_order_code:
|
||||
data = response_data.get('data', {})
|
||||
order_found = False
|
||||
|
||||
# 检查返回的数据结构,可能包含列表或其他结构
|
||||
if isinstance(data, dict):
|
||||
# 如果data是字典,可能包含records、list、data等字段
|
||||
records = data.get('records') or data.get('list') or data.get('data') or []
|
||||
if isinstance(records, list) and len(records) > 0:
|
||||
# 检查列表中是否包含指定的采购单号
|
||||
for item in records:
|
||||
if isinstance(item, dict):
|
||||
order_sn = item.get('order_sn') or item.get('orderSn') or item.get('orderSn')
|
||||
if order_sn == purchase_order_code:
|
||||
order_found = True
|
||||
break
|
||||
elif isinstance(data, list):
|
||||
# 如果data本身就是列表
|
||||
for item in data:
|
||||
if isinstance(item, dict):
|
||||
order_sn = item.get('order_sn') or item.get('orderSn') or item.get('orderSn')
|
||||
if order_sn == purchase_order_code:
|
||||
order_found = True
|
||||
break
|
||||
|
||||
if order_found:
|
||||
logging.info("✓ 断言通过:返回的数据中包含采购单号 {}".format(purchase_order_code))
|
||||
else:
|
||||
logging.warning("⚠ 警告:返回的数据中未找到采购单号: {},但接口调用成功".format(purchase_order_code))
|
||||
|
||||
logging.info("✓ 所有断言检查通过")
|
||||
print("✓ 查询成功,响应数据: {}".format(response_data))
|
||||
0
zhyy/test_case/TestCase/接口/SZPurchase/__init__.py
Normal file
0
zhyy/test_case/TestCase/接口/SZPurchase/__init__.py
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
19
zhyy/test_case/TestCase/接口/SZPurchase/index.py
Normal file
19
zhyy/test_case/TestCase/接口/SZPurchase/index.py
Normal file
@@ -0,0 +1,19 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import allure
|
||||
import logging
|
||||
|
||||
from zhyy.library.BusinessKw.SZPurchase.index import PurchaseIndex
|
||||
|
||||
|
||||
@allure.feature('深圳采购工作台首页')
|
||||
class Test_purchase_index(object):
|
||||
# config = ReadConfig.ReadConfig() # 调用读取配置文件的方法类
|
||||
test_case = PurchaseIndex()
|
||||
|
||||
def teardown_method(self):
|
||||
logging.info("-----------------------------End-------------------------------")
|
||||
|
||||
@allure.story("验证采购工作台待办任务与在办任务功能")
|
||||
def test_check_todo(self):
|
||||
get_purchase_data = self.test_case.kw_zhyy_get_todo(note="采购工作台首页待办任务PO与在办任务PO", user='purchase')
|
||||
0
zhyy/test_case/TestCase/接口/__init__.py
Normal file
0
zhyy/test_case/TestCase/接口/__init__.py
Normal file
BIN
zhyy/test_case/TestCase/接口/__pycache__/__init__.cpython-38.pyc
Normal file
BIN
zhyy/test_case/TestCase/接口/__pycache__/__init__.cpython-38.pyc
Normal file
Binary file not shown.
Binary file not shown.
14
zhyy/test_case/TestCase/接口/conftest.py
Normal file
14
zhyy/test_case/TestCase/接口/conftest.py
Normal file
@@ -0,0 +1,14 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
测试配置文件
|
||||
用于设置测试环境的路径和配置
|
||||
"""
|
||||
import os
|
||||
import sys
|
||||
|
||||
# 添加项目根目录到 Python 路径,确保能导入 zhyy 模块
|
||||
current_file_path = os.path.abspath(__file__)
|
||||
# 从 test_case/TestCase/接口/conftest.py 向上找到项目根目录 d:\zhyy
|
||||
project_root = os.path.abspath(os.path.join(os.path.dirname(current_file_path), '../../../..'))
|
||||
if project_root not in sys.path:
|
||||
sys.path.insert(0, project_root)
|
||||
0
zhyy/test_case/__init__.py
Normal file
0
zhyy/test_case/__init__.py
Normal file
BIN
zhyy/test_case/__pycache__/__init__.cpython-38.pyc
Normal file
BIN
zhyy/test_case/__pycache__/__init__.cpython-38.pyc
Normal file
Binary file not shown.
44
zhyy/test_case/jenkins_build.bat
Normal file
44
zhyy/test_case/jenkins_build.bat
Normal file
@@ -0,0 +1,44 @@
|
||||
@echo off
|
||||
REM Jenkins构建脚本(Windows)
|
||||
REM 用于在Jenkins中执行测试并生成Allure报告
|
||||
|
||||
setlocal enabledelayedexpansion
|
||||
|
||||
REM 设置工作目录
|
||||
if defined WORKSPACE (
|
||||
cd /d %WORKSPACE%
|
||||
) else (
|
||||
cd /d %~dp0..
|
||||
)
|
||||
|
||||
REM 进入测试目录
|
||||
cd zhyy\test_case
|
||||
|
||||
REM 运行测试(根据参数选择运行方式)
|
||||
if "%RUN_TYPE%"=="" set RUN_TYPE=all
|
||||
|
||||
if "%RUN_TYPE%"=="all" (
|
||||
python run_tests.py --all --no-report
|
||||
) else if "%RUN_TYPE%"=="feature" (
|
||||
python run_tests.py --feature "%FEATURE_NAME%" --no-report
|
||||
) else if "%RUN_TYPE%"=="story" (
|
||||
python run_tests.py --story "%STORY_NAME%" --no-report
|
||||
) else if "%RUN_TYPE%"=="dir" (
|
||||
python run_tests.py --dir "%DIR_PATH%" --no-report
|
||||
) else if "%RUN_TYPE%"=="file" (
|
||||
python run_tests.py --file "%FILE_PATH%" --no-report
|
||||
) else if "%RUN_TYPE%"=="keyword" (
|
||||
python run_tests.py --keyword "%KEYWORD%" --no-report
|
||||
) else if "%RUN_TYPE%"=="marker" (
|
||||
python run_tests.py --marker "%MARKER%" --no-report
|
||||
) else (
|
||||
echo 未知的运行类型: %RUN_TYPE%
|
||||
exit /b 1
|
||||
)
|
||||
|
||||
REM 生成Allure报告(Jenkins插件会自动处理,这里可选)
|
||||
REM allure generate reports\allure-results -o reports\allure-report --clean
|
||||
|
||||
echo 测试执行完成,Allure结果已保存到: reports\allure-results
|
||||
|
||||
endlocal
|
||||
47
zhyy/test_case/jenkins_build.sh
Normal file
47
zhyy/test_case/jenkins_build.sh
Normal file
@@ -0,0 +1,47 @@
|
||||
#!/bin/bash
|
||||
# Jenkins构建脚本(Linux/Mac)
|
||||
# 用于在Jenkins中执行测试并生成Allure报告
|
||||
|
||||
set -e # 遇到错误立即退出
|
||||
|
||||
# 设置工作目录
|
||||
cd ${WORKSPACE:-$(pwd)}
|
||||
|
||||
# 进入测试目录
|
||||
cd zhyy/test_case
|
||||
|
||||
# 运行测试(根据参数选择运行方式)
|
||||
RUN_TYPE=${RUN_TYPE:-all}
|
||||
|
||||
case ${RUN_TYPE} in
|
||||
all)
|
||||
python run_tests.py --all --no-report
|
||||
;;
|
||||
feature)
|
||||
python run_tests.py --feature "${FEATURE_NAME}" --no-report
|
||||
;;
|
||||
story)
|
||||
python run_tests.py --story "${STORY_NAME}" --no-report
|
||||
;;
|
||||
dir)
|
||||
python run_tests.py --dir "${DIR_PATH}" --no-report
|
||||
;;
|
||||
file)
|
||||
python run_tests.py --file "${FILE_PATH}" --no-report
|
||||
;;
|
||||
keyword)
|
||||
python run_tests.py --keyword "${KEYWORD}" --no-report
|
||||
;;
|
||||
marker)
|
||||
python run_tests.py --marker "${MARKER}" --no-report
|
||||
;;
|
||||
*)
|
||||
echo "未知的运行类型: ${RUN_TYPE}"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
# 生成Allure报告(Jenkins插件会自动处理,这里可选)
|
||||
# allure generate reports/allure-results -o reports/allure-report --clean || true
|
||||
|
||||
echo "测试执行完成,Allure结果已保存到: reports/allure-results"
|
||||
60
zhyy/test_case/reports/allure-report/app.js
Normal file
60
zhyy/test_case/reports/allure-report/app.js
Normal file
File diff suppressed because one or more lines are too long
4
zhyy/test_case/reports/allure-report/data/behaviors.csv
Normal file
4
zhyy/test_case/reports/allure-report/data/behaviors.csv
Normal file
@@ -0,0 +1,4 @@
|
||||
"Epic","Feature","Story","FAILED","BROKEN","PASSED","SKIPPED","UNKNOWN"
|
||||
"","深圳采购工作台首页","验证采购工作台待办任务与在办任务功能","0","0","2","0","0"
|
||||
"","深圳采购工作台采购订单页面","验证采购工作台采购订单页面列表查询","0","0","2","0","0"
|
||||
"","","","0","0","1","0","0"
|
||||
|
6
zhyy/test_case/reports/allure-report/data/suites.csv
Normal file
6
zhyy/test_case/reports/allure-report/data/suites.csv
Normal file
@@ -0,0 +1,6 @@
|
||||
"Status","Start Time","Stop Time","Duration in ms","Parent Suite","Suite","Sub Suite","Test Class","Test Method","Name","Description"
|
||||
"passed","Thu Jan 22 17:45:22 CST 2026","Thu Jan 22 17:45:24 CST 2026","2362","zhyy.test_case.TestCase.接口.SZPurchase","index","Test_purchase_index","","","test_check_todo",""
|
||||
"passed","Thu Jan 22 18:16:40 CST 2026","Thu Jan 22 18:16:41 CST 2026","528","zhyy.test_case.TestCase.接口.SZPurchase","PurchaseOrderManage","Test_purchase_order","","","test_check_purchase_order_page",""
|
||||
"passed","Thu Jan 22 16:47:07 CST 2026","Thu Jan 22 16:47:07 CST 2026","0","zhyy.test_case.TestCase","test_sample","","","","test_sample",""
|
||||
"passed","Thu Jan 22 18:16:38 CST 2026","Thu Jan 22 18:16:40 CST 2026","2656","zhyy.test_case.TestCase.接口.SZPurchase","index","Test_purchase_index","","","test_check_todo",""
|
||||
"passed","Thu Jan 22 17:45:24 CST 2026","Thu Jan 22 17:45:25 CST 2026","530","zhyy.test_case.TestCase.接口.SZPurchase","PurchaseOrderManage","Test_purchase_order","","","test_check_purchase_order_page",""
|
||||
|
1
zhyy/test_case/reports/allure-report/favicon.ico
Normal file
1
zhyy/test_case/reports/allure-report/favicon.ico
Normal file
@@ -0,0 +1 @@
|
||||
module.exports = __webpack_public_path__ + "favicon.ico";
|
||||
150
zhyy/test_case/reports/allure-report/plugins/behaviors/index.js
Normal file
150
zhyy/test_case/reports/allure-report/plugins/behaviors/index.js
Normal file
@@ -0,0 +1,150 @@
|
||||
'use strict';
|
||||
|
||||
allure.api.addTranslation('en', {
|
||||
tab: {
|
||||
behaviors: {
|
||||
name: 'Behaviors'
|
||||
}
|
||||
},
|
||||
widget: {
|
||||
behaviors: {
|
||||
name: 'Features by stories',
|
||||
showAll: 'show all'
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
allure.api.addTranslation('ru', {
|
||||
tab: {
|
||||
behaviors: {
|
||||
name: 'Функциональность'
|
||||
}
|
||||
},
|
||||
widget: {
|
||||
behaviors: {
|
||||
name: 'Функциональность',
|
||||
showAll: 'показать все'
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
allure.api.addTranslation('zh', {
|
||||
tab: {
|
||||
behaviors: {
|
||||
name: '功能'
|
||||
}
|
||||
},
|
||||
widget: {
|
||||
behaviors: {
|
||||
name: '特性场景',
|
||||
showAll: '显示所有'
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
allure.api.addTranslation('de', {
|
||||
tab: {
|
||||
behaviors: {
|
||||
name: 'Verhalten'
|
||||
}
|
||||
},
|
||||
widget: {
|
||||
behaviors: {
|
||||
name: 'Features nach Stories',
|
||||
showAll: 'Zeige alle'
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
allure.api.addTranslation('he', {
|
||||
tab: {
|
||||
behaviors: {
|
||||
name: 'התנהגויות'
|
||||
}
|
||||
},
|
||||
widget: {
|
||||
behaviors: {
|
||||
name: 'תכונות לפי סיפורי משתמש',
|
||||
showAll: 'הצג הכול'
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
allure.api.addTranslation('br', {
|
||||
tab: {
|
||||
behaviors: {
|
||||
name: 'Comportamentos'
|
||||
}
|
||||
},
|
||||
widget: {
|
||||
behaviors: {
|
||||
name: 'Funcionalidades por história',
|
||||
showAll: 'Mostrar tudo'
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
allure.api.addTranslation('ja', {
|
||||
tab: {
|
||||
behaviors: {
|
||||
name: '振る舞い'
|
||||
}
|
||||
},
|
||||
widget: {
|
||||
behaviors: {
|
||||
name: 'ストーリー別の機能',
|
||||
showAll: '全て表示'
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
allure.api.addTranslation('es', {
|
||||
tab: {
|
||||
behaviors: {
|
||||
name: 'Funcionalidades'
|
||||
}
|
||||
},
|
||||
widget: {
|
||||
behaviors: {
|
||||
name: 'Funcionalidades por Historias de Usuario',
|
||||
showAll: 'mostrar todo'
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
allure.api.addTranslation('kr', {
|
||||
tab: {
|
||||
behaviors: {
|
||||
name: '동작'
|
||||
}
|
||||
},
|
||||
widget: {
|
||||
behaviors: {
|
||||
name: '스토리별 기능',
|
||||
showAll: '전체 보기'
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
allure.api.addTab('behaviors', {
|
||||
title: 'tab.behaviors.name', icon: 'fa fa-list',
|
||||
route: 'behaviors(/)(:testGroup)(/)(:testResult)(/)(:testResultTab)(/)',
|
||||
onEnter: (function (testGroup, testResult, testResultTab) {
|
||||
return new allure.components.TreeLayout({
|
||||
testGroup: testGroup,
|
||||
testResult: testResult,
|
||||
testResultTab: testResultTab,
|
||||
tabName: 'tab.behaviors.name',
|
||||
baseUrl: 'behaviors',
|
||||
url: 'data/behaviors.json',
|
||||
csvUrl: 'data/behaviors.csv'
|
||||
});
|
||||
})
|
||||
});
|
||||
|
||||
allure.api.addWidget('widgets', 'behaviors', allure.components.WidgetStatusView.extend({
|
||||
rowTag: 'a',
|
||||
title: 'widget.behaviors.name',
|
||||
baseUrl: 'behaviors',
|
||||
showLinks: true
|
||||
}));
|
||||
@@ -0,0 +1,88 @@
|
||||
'use strict';
|
||||
|
||||
allure.api.addTranslation('en', {
|
||||
tab: {
|
||||
packages: {
|
||||
name: 'Packages'
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
allure.api.addTranslation('ru', {
|
||||
tab: {
|
||||
packages: {
|
||||
name: 'Пакеты'
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
allure.api.addTranslation('zh', {
|
||||
tab: {
|
||||
packages: {
|
||||
name: '包'
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
allure.api.addTranslation('de', {
|
||||
tab: {
|
||||
packages: {
|
||||
name: 'Pakete'
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
allure.api.addTranslation('he', {
|
||||
tab: {
|
||||
packages: {
|
||||
name: 'חבילות'
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
allure.api.addTranslation('br', {
|
||||
tab: {
|
||||
packages: {
|
||||
name: 'Pacotes'
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
allure.api.addTranslation('ja', {
|
||||
tab: {
|
||||
packages: {
|
||||
name: 'パッケージ'
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
allure.api.addTranslation('es', {
|
||||
tab: {
|
||||
packages: {
|
||||
name: 'Paquetes'
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
allure.api.addTranslation('kr', {
|
||||
tab: {
|
||||
packages: {
|
||||
name: '패키지'
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
allure.api.addTab('packages', {
|
||||
title: 'tab.packages.name', icon: 'fa fa-align-left',
|
||||
route: 'packages(/)(:testGroup)(/)(:testResult)(/)(:testResultTab)(/)',
|
||||
onEnter: (function (testGroup, testResult, testResultTab) {
|
||||
return new allure.components.TreeLayout({
|
||||
testGroup: testGroup,
|
||||
testResult: testResult,
|
||||
testResultTab: testResultTab,
|
||||
tabName: 'tab.packages.name',
|
||||
baseUrl: 'packages',
|
||||
url: 'data/packages.json'
|
||||
});
|
||||
})
|
||||
});
|
||||
@@ -0,0 +1,97 @@
|
||||
(function () {
|
||||
var settings = allure.getPluginSettings('screen-diff', {diffType: 'diff'});
|
||||
|
||||
function renderImage(src) {
|
||||
return '<div class="screen-diff__container">' +
|
||||
'<img class="screen-diff__image" src="data/attachments/' + src + '">' +
|
||||
'</div>';
|
||||
}
|
||||
|
||||
function renderDiffContent(type, data) {
|
||||
function findImage(name) {
|
||||
if (data.testStage && data.testStage.attachments) {
|
||||
return data.testStage.attachments.filter(function (attachment) {
|
||||
return attachment.name === name;
|
||||
})[0];
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
var diffImage = findImage('diff');
|
||||
var actualImage = findImage('actual');
|
||||
var expectedImage = findImage('expected');
|
||||
|
||||
if (!diffImage && !actualImage && !expectedImage) {
|
||||
return '<span>Diff, actual and expected image have not been provided.</span>';
|
||||
}
|
||||
|
||||
if (type === 'diff') {
|
||||
if (!diffImage) {
|
||||
return renderImage(actualImage.source);
|
||||
}
|
||||
return renderImage(diffImage.source);
|
||||
}
|
||||
if (type === 'overlay') {
|
||||
return '<div class="screen-diff__overlay screen-diff__container">' +
|
||||
'<img class="screen-diff__image" src="data/attachments/' + expectedImage.source + '">' +
|
||||
'<div class="screen-diff__image-over">' +
|
||||
'<img class="screen-diff__image" src="data/attachments/' + actualImage.source + '">' +
|
||||
'</div>' +
|
||||
'</div>';
|
||||
}
|
||||
}
|
||||
|
||||
var ScreenDiffView = Backbone.Marionette.View.extend({
|
||||
className: 'pane__section',
|
||||
events: {
|
||||
'click [name="screen-diff-type"]': 'onDiffTypeChange',
|
||||
'mousemove .screen-diff__overlay': 'onOverlayMove'
|
||||
},
|
||||
templateContext: function () {
|
||||
return {
|
||||
diffType: settings.get('diffType')
|
||||
}
|
||||
},
|
||||
template: function (data) {
|
||||
var testType = data.labels.filter(function (label) {
|
||||
return label.name === 'testType'
|
||||
})[0];
|
||||
|
||||
if (!testType || testType.value !== 'screenshotDiff') {
|
||||
return '';
|
||||
}
|
||||
|
||||
return '<h3 class="pane__section-title">Screen Diff</h3>' +
|
||||
'<div class="screen-diff__content">' +
|
||||
'<div class="screen-diff__switchers">' +
|
||||
'<label><input type="radio" name="screen-diff-type" value="diff"> Show diff</label>' +
|
||||
'<label><input type="radio" name="screen-diff-type" value="overlay"> Show overlay</label>' +
|
||||
'</div>' +
|
||||
renderDiffContent(data.diffType, data) +
|
||||
'</div>';
|
||||
},
|
||||
adjustImageSize: function (event) {
|
||||
var overImage = this.$(event.target);
|
||||
overImage.width(overImage.width());
|
||||
},
|
||||
onRender: function () {
|
||||
const diffType = settings.get('diffType');
|
||||
this.$('[name="screen-diff-type"][value="' + diffType + '"]').prop('checked', true);
|
||||
if (diffType === 'overlay') {
|
||||
this.$('.screen-diff__image-over img').on('load', this.adjustImageSize.bind(this));
|
||||
}
|
||||
},
|
||||
onOverlayMove: function (event) {
|
||||
var pageX = event.pageX;
|
||||
var containerScroll = this.$('.screen-diff__container').scrollLeft();
|
||||
var elementX = event.currentTarget.getBoundingClientRect().left;
|
||||
var delta = pageX - elementX + containerScroll;
|
||||
this.$('.screen-diff__image-over').width(delta);
|
||||
},
|
||||
onDiffTypeChange: function (event) {
|
||||
settings.save('diffType', event.target.value);
|
||||
this.render();
|
||||
}
|
||||
});
|
||||
allure.api.addTestResultBlock(ScreenDiffView, {position: 'before'});
|
||||
})();
|
||||
@@ -0,0 +1,26 @@
|
||||
.screen-diff__switchers {
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
|
||||
.screen-diff__switchers label + label {
|
||||
margin-left: 1em;
|
||||
}
|
||||
|
||||
.screen-diff__overlay {
|
||||
position: relative;
|
||||
cursor: col-resize;
|
||||
}
|
||||
|
||||
.screen-diff__container {
|
||||
overflow-x: auto;
|
||||
}
|
||||
|
||||
.screen-diff__image-over {
|
||||
top: 0;
|
||||
left: 0;
|
||||
bottom: 0;
|
||||
background: #fff;
|
||||
position: absolute;
|
||||
overflow: hidden;
|
||||
box-shadow: 2px 0 1px -1px #aaa;
|
||||
}
|
||||
6
zhyy/test_case/reports/allure-report/styles.css
Normal file
6
zhyy/test_case/reports/allure-report/styles.css
Normal file
File diff suppressed because one or more lines are too long
7
zhyy/test_case/run_all.bat
Normal file
7
zhyy/test_case/run_all.bat
Normal file
@@ -0,0 +1,7 @@
|
||||
@echo off
|
||||
chcp 65001 >nul
|
||||
echo ========================================
|
||||
echo 运行所有测试用例
|
||||
echo ========================================
|
||||
python run_tests.py --all --report
|
||||
pause
|
||||
7
zhyy/test_case/run_purchase.bat
Normal file
7
zhyy/test_case/run_purchase.bat
Normal file
@@ -0,0 +1,7 @@
|
||||
@echo off
|
||||
chcp 65001 >nul
|
||||
echo ========================================
|
||||
echo 运行采购相关测试用例
|
||||
echo ========================================
|
||||
python run_tests.py --dir "接口/SZPurchase" --report
|
||||
pause
|
||||
328
zhyy/test_case/run_tests.py
Normal file
328
zhyy/test_case/run_tests.py
Normal file
@@ -0,0 +1,328 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
统一测试执行文件
|
||||
支持批量运行所有用例、按标签运行、按目录运行等
|
||||
"""
|
||||
import os
|
||||
import sys
|
||||
import subprocess
|
||||
import argparse
|
||||
from pathlib import Path
|
||||
|
||||
# 添加项目根目录到 Python 路径
|
||||
current_file_path = os.path.abspath(__file__)
|
||||
project_root = os.path.abspath(os.path.join(os.path.dirname(current_file_path), '../../'))
|
||||
if project_root not in sys.path:
|
||||
sys.path.insert(0, project_root)
|
||||
|
||||
# 测试目录
|
||||
TEST_CASE_DIR = 'zhyy/test_case/TestCase'
|
||||
# 报告目录
|
||||
REPORT_DIR = os.path.join(os.path.dirname(current_file_path), 'reports')
|
||||
ALLURE_RESULTS_DIR = os.path.join(REPORT_DIR, 'allure-results')
|
||||
ALLURE_REPORT_DIR = os.path.join(REPORT_DIR, 'allure-report')
|
||||
|
||||
|
||||
def ensure_dirs():
|
||||
"""确保报告目录存在"""
|
||||
os.makedirs(ALLURE_RESULTS_DIR, exist_ok=True)
|
||||
os.makedirs(ALLURE_REPORT_DIR, exist_ok=True)
|
||||
|
||||
|
||||
def run_pytest(args_list):
|
||||
"""执行pytest命令"""
|
||||
# 基础pytest命令
|
||||
# 设置PYTHONPATH环境变量,确保能导入zhyy模块
|
||||
env = os.environ.copy()
|
||||
if 'PYTHONPATH' in env:
|
||||
env['PYTHONPATH'] = project_root + os.pathsep + env['PYTHONPATH']
|
||||
else:
|
||||
env['PYTHONPATH'] = project_root
|
||||
|
||||
# 检测是否在Jenkins环境中
|
||||
is_jenkins = 'JENKINS_URL' in env or 'BUILD_NUMBER' in env
|
||||
if is_jenkins:
|
||||
print("检测到Jenkins环境,使用Jenkins配置...")
|
||||
# 在Jenkins中,报告路径使用绝对路径
|
||||
if 'WORKSPACE' in env:
|
||||
workspace = env['WORKSPACE']
|
||||
# 确保使用Jenkins工作空间的报告目录
|
||||
global ALLURE_RESULTS_DIR, ALLURE_REPORT_DIR
|
||||
ALLURE_RESULTS_DIR = os.path.join(workspace, 'zhyy', 'test_case', 'reports', 'allure-results')
|
||||
ALLURE_REPORT_DIR = os.path.join(workspace, 'zhyy', 'test_case', 'reports', 'allure-report')
|
||||
ensure_dirs()
|
||||
|
||||
cmd = ['python', '-m', 'pytest'] + args_list
|
||||
|
||||
print("=" * 80)
|
||||
print("执行命令: {}".format(' '.join(cmd)))
|
||||
print("命令列表: {}".format(cmd))
|
||||
print("测试目录: {}".format(TEST_CASE_DIR))
|
||||
print("测试目录是否存在: {}".format(os.path.exists(TEST_CASE_DIR)))
|
||||
if is_jenkins:
|
||||
print("Jenkins工作空间: {}".format(env.get('WORKSPACE', 'N/A')))
|
||||
print("构建编号: {}".format(env.get('BUILD_NUMBER', 'N/A')))
|
||||
print("PYTHONPATH: {}".format(env.get('PYTHONPATH')))
|
||||
print("Allure结果目录: {}".format(ALLURE_RESULTS_DIR))
|
||||
print("当前工作目录: {}".format(os.getcwd()))
|
||||
print("=" * 80)
|
||||
|
||||
# 使用 shell=True 来执行命令,确保能正确处理路径和参数
|
||||
result = subprocess.run(' '.join(cmd), shell=True, cwd=project_root, env=env)
|
||||
return result.returncode
|
||||
|
||||
|
||||
def find_test_files(directory):
|
||||
"""递归查找所有测试文件"""
|
||||
test_files = []
|
||||
for root, dirs, files in os.walk(directory):
|
||||
for file in files:
|
||||
if file.endswith('.py'):
|
||||
# 检查文件中是否包含测试函数
|
||||
file_path = os.path.join(root, file)
|
||||
try:
|
||||
with open(file_path, 'r', encoding='utf-8') as f:
|
||||
content = f.read()
|
||||
if 'def test_' in content or 'class Test' in content:
|
||||
test_files.append(file_path)
|
||||
except:
|
||||
pass
|
||||
return test_files
|
||||
|
||||
|
||||
def run_all_tests():
|
||||
"""运行所有测试用例"""
|
||||
print("运行所有测试用例...")
|
||||
# 递归查找所有测试文件
|
||||
test_files = find_test_files(TEST_CASE_DIR)
|
||||
if not test_files:
|
||||
print("未找到测试文件")
|
||||
return 1
|
||||
|
||||
print(f"找到 {len(test_files)} 个测试文件:")
|
||||
for file in test_files:
|
||||
print(f" - {file}")
|
||||
|
||||
args = [
|
||||
*test_files,
|
||||
'-v', # 详细输出
|
||||
'--tb=short', # 简短的错误信息
|
||||
f'--alluredir={ALLURE_RESULTS_DIR}', # allure结果目录
|
||||
]
|
||||
return run_pytest(args)
|
||||
|
||||
|
||||
def run_by_feature(feature_name):
|
||||
"""按allure feature标签运行"""
|
||||
print("按feature标签运行: {}".format(feature_name))
|
||||
args = [
|
||||
TEST_CASE_DIR,
|
||||
'-v',
|
||||
'--tb=short',
|
||||
f'--allure-features={feature_name}',
|
||||
f'--alluredir={ALLURE_RESULTS_DIR}',
|
||||
]
|
||||
return run_pytest(args)
|
||||
|
||||
|
||||
def run_by_story(story_name):
|
||||
"""按allure story标签运行"""
|
||||
print("按story标签运行: {}".format(story_name))
|
||||
args = [
|
||||
TEST_CASE_DIR,
|
||||
'-v',
|
||||
'--tb=short',
|
||||
f'--allure-stories={story_name}',
|
||||
f'--alluredir={ALLURE_RESULTS_DIR}',
|
||||
]
|
||||
return run_pytest(args)
|
||||
|
||||
|
||||
def run_by_marker(marker):
|
||||
"""按pytest标记运行"""
|
||||
print("按pytest标记运行: {}".format(marker))
|
||||
args = [
|
||||
TEST_CASE_DIR,
|
||||
'-v',
|
||||
'--tb=short',
|
||||
f'-m={marker}',
|
||||
f'--alluredir={ALLURE_RESULTS_DIR}',
|
||||
]
|
||||
return run_pytest(args)
|
||||
|
||||
|
||||
def run_by_dir(directory):
|
||||
"""按目录运行"""
|
||||
full_path = os.path.join(TEST_CASE_DIR, directory)
|
||||
if not os.path.exists(full_path):
|
||||
print("错误: 目录不存在: {}".format(full_path))
|
||||
return 1
|
||||
|
||||
print("按目录运行: {}".format(directory))
|
||||
args = [
|
||||
full_path,
|
||||
'-v',
|
||||
'--tb=short',
|
||||
f'--alluredir={ALLURE_RESULTS_DIR}',
|
||||
]
|
||||
return run_pytest(args)
|
||||
|
||||
|
||||
def run_by_file(file_path):
|
||||
"""按文件运行"""
|
||||
full_path = os.path.join(TEST_CASE_DIR, file_path)
|
||||
if not os.path.exists(full_path):
|
||||
print("错误: 文件不存在: {}".format(full_path))
|
||||
return 1
|
||||
|
||||
print("按文件运行: {}".format(file_path))
|
||||
args = [
|
||||
full_path,
|
||||
'-v',
|
||||
'--tb=short',
|
||||
f'--alluredir={ALLURE_RESULTS_DIR}',
|
||||
]
|
||||
return run_pytest(args)
|
||||
|
||||
|
||||
def run_by_keyword(keyword):
|
||||
"""按关键字运行(匹配文件名或类名)"""
|
||||
print("按关键字运行: {}".format(keyword))
|
||||
args = [
|
||||
TEST_CASE_DIR,
|
||||
'-v',
|
||||
'--tb=short',
|
||||
f'-k={keyword}',
|
||||
f'--alluredir={ALLURE_RESULTS_DIR}',
|
||||
]
|
||||
return run_pytest(args)
|
||||
|
||||
|
||||
def generate_allure_report():
|
||||
"""生成allure报告"""
|
||||
print("生成Allure报告...")
|
||||
cmd = [
|
||||
'allure',
|
||||
'generate',
|
||||
ALLURE_RESULTS_DIR,
|
||||
'-o',
|
||||
ALLURE_REPORT_DIR,
|
||||
'--clean'
|
||||
]
|
||||
|
||||
try:
|
||||
# 使用shell=True来执行命令,确保使用正确的环境变量
|
||||
result = subprocess.run(' '.join(cmd), shell=True, check=True)
|
||||
print("Allure报告生成成功: {}".format(ALLURE_REPORT_DIR))
|
||||
print("打开报告命令: allure open {}".format(ALLURE_REPORT_DIR))
|
||||
return 0
|
||||
except subprocess.CalledProcessError as e:
|
||||
print("生成Allure报告失败: {}".format(e))
|
||||
return 1
|
||||
except FileNotFoundError:
|
||||
print("警告: 未找到allure命令,请先安装allure")
|
||||
print("安装方法: https://docs.qameta.io/allure/")
|
||||
return 1
|
||||
|
||||
|
||||
def open_allure_report():
|
||||
"""打开allure报告"""
|
||||
print("打开Allure报告...")
|
||||
cmd = ['allure', 'open', ALLURE_REPORT_DIR]
|
||||
|
||||
try:
|
||||
# 使用shell=True来执行命令,确保使用正确的环境变量
|
||||
subprocess.Popen(' '.join(cmd), shell=True)
|
||||
print("Allure报告已在浏览器中打开")
|
||||
except FileNotFoundError:
|
||||
print("警告: 未找到allure命令,请先安装allure")
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(
|
||||
description='统一测试执行工具',
|
||||
formatter_class=argparse.RawDescriptionHelpFormatter,
|
||||
epilog="""
|
||||
使用示例:
|
||||
# 运行所有测试
|
||||
python run_tests.py --all
|
||||
|
||||
# 按feature标签运行
|
||||
python run_tests.py --feature "深圳采购工作台采购订单页面"
|
||||
|
||||
# 按story标签运行
|
||||
python run_tests.py --story "验证采购工作台采购订单页面列表查询"
|
||||
|
||||
# 按目录运行
|
||||
python run_tests.py --dir "接口/SZPurchase"
|
||||
|
||||
# 按文件运行
|
||||
python run_tests.py --file "接口/SZPurchase/PurchaseOrderManage.py"
|
||||
|
||||
# 按关键字运行
|
||||
python run_tests.py --keyword "purchase"
|
||||
|
||||
# 按pytest标记运行
|
||||
python run_tests.py --marker "smoke"
|
||||
|
||||
# 生成并打开报告
|
||||
python run_tests.py --all --report --open
|
||||
"""
|
||||
)
|
||||
|
||||
# 运行选项(不强制要求,默认运行所有测试)
|
||||
run_group = parser.add_mutually_exclusive_group(required=False)
|
||||
run_group.add_argument('--all', action='store_true', help='运行所有测试用例(默认)')
|
||||
run_group.add_argument('--feature', type=str, help='按allure feature标签运行')
|
||||
run_group.add_argument('--story', type=str, help='按allure story标签运行')
|
||||
run_group.add_argument('--dir', type=str, help='按目录运行(相对于TestCase目录)')
|
||||
run_group.add_argument('--file', type=str, help='按文件运行(相对于TestCase目录)')
|
||||
run_group.add_argument('--keyword', type=str, help='按关键字运行(匹配文件名或类名)')
|
||||
run_group.add_argument('--marker', type=str, help='按pytest标记运行')
|
||||
|
||||
# 报告选项
|
||||
parser.add_argument('--report', action='store_true', help='生成Allure报告')
|
||||
parser.add_argument('--open', action='store_true', help='打开Allure报告(需要先使用--report)')
|
||||
parser.add_argument('--no-report', action='store_true', help='不生成Allure报告(默认会生成)')
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
# 确保目录存在
|
||||
ensure_dirs()
|
||||
|
||||
# 执行测试(如果没有指定选项,默认运行所有测试)
|
||||
exit_code = 0
|
||||
if args.feature:
|
||||
exit_code = run_by_feature(args.feature)
|
||||
elif args.story:
|
||||
exit_code = run_by_story(args.story)
|
||||
elif args.dir:
|
||||
exit_code = run_by_dir(args.dir)
|
||||
elif args.file:
|
||||
exit_code = run_by_file(args.file)
|
||||
elif args.keyword:
|
||||
exit_code = run_by_keyword(args.keyword)
|
||||
elif args.marker:
|
||||
exit_code = run_by_marker(args.marker)
|
||||
else:
|
||||
# 默认运行所有测试
|
||||
exit_code = run_all_tests()
|
||||
|
||||
# 生成报告
|
||||
if args.report or (not args.no_report and exit_code == 0):
|
||||
generate_allure_report()
|
||||
if args.open:
|
||||
open_allure_report()
|
||||
|
||||
print("=" * 80)
|
||||
if exit_code == 0:
|
||||
print("✓ 测试执行完成")
|
||||
else:
|
||||
print("✗ 测试执行失败,退出码: {}".format(exit_code))
|
||||
print("=" * 80)
|
||||
|
||||
sys.exit(exit_code)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
Reference in New Issue
Block a user