Commit 56e41b49 by mc183225678

接口自动化框架-V-1.0.0

parent 3f369665
# -*-coding:utf-8 -*- #
# ---------------------------------------------------------------------------
# ProjectName: test_57
# FileName: __init__.py
# Author: xxxxxxx
# Datetime: 2023/11/3 14:00
# Description:
#
# ---------------------------------------------------------------------------
# -*-coding:utf-8 -*- #
# ---------------------------------------------------------------------------
# ProjectName: test_57
# FileName: __init__.py
# Author: xxxxxxx
# Datetime: 2023/11/3 14:01
# Description:
#
# ---------------------------------------------------------------------------
from InterfaceAutoTest.common.log import write_log
log = write_log()
# -*-coding:utf-8 -*- #
# ---------------------------------------------------------------------------
# ProjectName: test_57
# FileName: db.py
# Author: xxxxxxx
# Datetime: 2023/11/3 14:23
# Description:
#
# ---------------------------------------------------------------------------
import pymysql
from InterfaceAutoTest.common import log
from InterfaceAutoTest.common.read_ini import ReadIni
from InterfaceAutoTest.data_config.settings import *
class DB:
def __init__(self):
"""链接数据库,获取链接对象和游标对象"""
read_ini = ReadIni()
try:
self.conn = pymysql.connect(
host=read_ini.get_sql_message(HOST),
port=int(read_ini.get_sql_message(PORT)),
user=read_ini.get_sql_message(USER),
password=read_ini.get_sql_message(PWD),
database=read_ini.get_sql_message(DATABASE),
charset="utf8"
)
self.cursor = self.conn.cursor()
except:
log.error("链接数据库错误或者获取游标对象失败!!!,请求察看数据库的链接配置.")
raise pymysql.MySQLError("链接数据库错误或者获取游标对象失败!!!,请求察看数据库的链接配置.")
def close(self):
self.cursor.close()
self.conn.close()
def delete(self, sql):
"""执行删除的sql语句"""
try:
self.cursor.execute(sql)
self.conn.commit()
except:
log.error("执行删除的sql语句错误,请察看对应的删除的sql语句")
raise ValueError("执行删除的sql语句错误,请察看对应的删除的sql语句")
def select(self, sql, num=1):
"""执行查询的sql语句"""
try:
self.cursor.execute(sql)
select_result = self.cursor.fetchall()
if select_result and num == 1:
return select_result[0][0]
elif select_result and num == 2:
return select_result[0][0], select_result[0][1]
elif select_result and num > 3:
return select_result
except:
log.error("执行查询的sql语句错误,请察看对应的查询的sql语句")
raise ValueError("执行查询的sql语句错误,请察看对应的查询的sql语句")
if __name__ == '__main__':
db = DB()
sql = """SELECT * FROM uc_demension LIMIT 1"""
print(db.select(sql))
# -*-coding:utf-8 -*- #
# ---------------------------------------------------------------------------
# ProjectName: test_57
# FileName: log.py
# Author: xxxxxxx
# Datetime: 2023/11/3 14:02
# Description:
#
# ---------------------------------------------------------------------------
import logging
import os
def write_log():
"""创建写入日志对象"""
logger = logging.getLogger(name="黄总")
logger.level = logging.NOTSET
log_path = os.path.join(os.path.dirname(os.path.dirname(__file__)), "report/log/日志汇总.log")
handler = logging.FileHandler(log_path, mode="a", encoding="utf-8")
format = logging.Formatter('%(asctime)s - %(filename)s[line:%(lineno)d] - %(levelname)s: %(message)s - %(name)s')
handler.setFormatter(format)
logger.addHandler(handler)
return logger
# -*-coding:utf-8 -*- #
# ---------------------------------------------------------------------------
# ProjectName: test_57
# FileName: read_excel.py
# Author: xxxxxxx
# Datetime: 2023/11/3 14:31
# Description:
#
# ---------------------------------------------------------------------------
import openpyxl
from InterfaceAutoTest.data_config.settings import *
from InterfaceAutoTest.common import log
from InterfaceAutoTest.common.read_ini import ReadIni
from InterfaceAutoTest.common.read_json import read_json
class ReadExcel:
def __init__(self, table_nme, excel_path=None):
"""获取数据配置层中除了ini文件以外的所有文件的路径,再获取excel的工作表,再读取所有的json文件"""
self.read_ini = ReadIni()
excel_path = self.read_ini.get_file_path(EXCEL)
case_data_path = self.read_ini.get_file_path(CASE)
expect_data_path = self.read_ini.get_file_path(EXPECT)
sql_data_path = self.read_ini.get_file_path(SQL)
# 获取工作表名称
# table_name = self.read_ini.get_table_name(TABLE_NAME)
table_name = table_nme
wb = openpyxl.load_workbook(excel_path)
try:
self.ws = wb[table_name]
except:
log.error("获取工作表失败,请察看工作表名称是否配置正确!!!")
raise KeyError("获取工作表失败,请察看工作表名称是否配置正确!!!")
self.case_data_dict = read_json(case_data_path)
self.expect_data_dict = read_json(expect_data_path)
self.sql_data_dict = read_json(sql_data_path)
def __get_cell_value(self, column: str, row: int) -> str:
"""获取指定单元格数据"""
try:
value = self.ws[column+str(row)].value
if value is None:
return None
elif value.strip():
return value.strip()
except:
log.error("获取指定单元格数据失败,请察看输入的列号和行号是否正确!!")
raise KeyError("获取指定单元格数据失败,请察看输入的列号和行号是否正确!!")
def module_name(self, row):
"""根据行号,获取模块名称"""
return self.__get_cell_value(MODULE, row)
def api_name(self, row):
"""根据行号,获取接口名称"""
return self.__get_cell_value(API, row)
def title(self, row):
"""根据行号,获取用例标题"""
return self.__get_cell_value(TITLE, row)
def level(self, row):
"""根据行号,获取用例等级"""
return self.__get_cell_value(LEVEL, row)
def case_url(self, row):
"""根据行号,获取请求的url"""
return self.read_ini.get_host(URL_HOST_CUSTOM) + self.__get_cell_value(URL, row)
def case_method(self, row):
"""根据行号,获取请求方法"""
return self.__get_cell_value(METHOD, row)
def case_mime(self, row):
"""根据行号,获取媒体类型"""
mime = self.__get_cell_value(MIME, row)
if mime:
return mime.lower()
def case_data(self, row):
"""根据行号,获取用例数据"""
case_data_key = self.__get_cell_value(CASE_DATA, row)
if case_data_key:
module_name = self.module_name(row)
api_name = self.api_name(row)
try:
return self.case_data_dict[module_name][api_name][case_data_key]
except:
log.error("请察看是否配置了用例数据!!!")
raise KeyError("请察看是否配置了用例数据!!!")
def expect_data(self, row):
"""根据行号,获取期望数据"""
expect_data_key = self.__get_cell_value(EXPECT_DATA, row)
module_name = self.module_name(row)
api_name = self.api_name(row)
try:
return self.expect_data_dict[module_name][api_name][expect_data_key]
except:
log.error("请察看是否配置了期望数据!!!")
raise KeyError("请察看是否配置了期望数据!!!")
def sql_type(self, row):
"""根据行号,获取sql语句类型"""
sql_type_value = self.__get_cell_value(SQL_TYPE, row)
if sql_type_value:
return sql_type_value.lower()
def sql_data(self, row):
"""根据行号,获取sql语句"""
sql_data_key = self.__get_cell_value(SQL_DATA, row)
if sql_data_key:
module_name = self.module_name(row)
api_name = self.api_name(row)
try:
return self.sql_data_dict[module_name][api_name][sql_data_key]
except:
log.error("请察看是否配置了sql数据!!!")
raise KeyError("请察看是否配置了sql数据!!!")
def update_key(self, row):
"""根据行号,获取更新的key"""
return self.__get_cell_value(UPDATE_KEY, row)
def get_data(self):
"""将测试数据存放在一个二维列表中"""
list_data = []
try:
for row in range(2, self.ws.max_row + 1):
# module_name
module_name = self.module_name(row)
# api
api_name = self.api_name(row)
# title
title = self.title(row)
# level
level = self.level(row)
# url
case_url = self.case_url(row)
# method
case_method = self.case_method(row)
# mime
case_mime = self.case_mime(row)
# case_data
case_data = self.case_data(row)
# expect_data
expect_data = self.expect_data(row)
# sql_type
sql_type = self.sql_type(row)
# sql_data
sql_data = self.sql_data(row)
# update_key
update_key = self.update_key(row)
list_data.append(
[module_name, api_name, title, level, case_url, case_method, case_mime, case_data, expect_data, sql_type, sql_data, update_key])
else:
return list_data
except:
log.error("请察看excel中是否存在空行,如果存在,请删除空行!!")
raise TypeError("请察看excel中是否存在空行,如果存在,请删除空行!!")
if __name__ == '__main__':
excel = ReadExcel()
print(excel.get_data())
\ No newline at end of file
# -*-coding:utf-8 -*- #
# ---------------------------------------------------------------------------
# ProjectName: test_57
# FileName: read_ini.py
# Author: xxxxxxx
# Datetime: 2023/11/3 14:05
# Description:
#
# ---------------------------------------------------------------------------
import configparser
import os
from InterfaceAutoTest.common import log
from InterfaceAutoTest.data_config.settings import *
class ReadIni:
def __init__(self):
"""读取ini文件"""
self.data_config_path = os.path.join(os.path.dirname(os.path.dirname(__file__)), "data_config")
ini_path = os.path.join(self.data_config_path, "config.ini")
self.conf = configparser.ConfigParser()
self.conf.read(ini_path, encoding="utf-8")
def get_file_path(self, key):
"""根据key,获取file节点下文件的路径"""
try:
file_name = self.conf.get(FILE, key)
except:
log.error("输入file节点下的key,错误,请求察看配置文件~!!!")
raise KeyError("输入file节点下的key,错误,请求察看配置文件~!!!")
file_path = os.path.join(self.data_config_path, file_name)
if os.path.isfile(file_path):
return file_path
else:
log.error("获取file节点下,文件的路径错误,请察看配置文件是否配置正确~!!!")
raise FileExistsError("获取file节点下,文件的路径错误,请察看配置文件是否配置正确~!!!")
def get_host(self, key):
"""根据key,获取域名"""
try:
return self.conf.get(URL_HOST, key)
except:
log.error("输入host节点下的key,错误,请求察看配置文件~!!!")
raise KeyError("输入host节点下的key,错误,请求察看配置文件~!!!")
def get_table_name(self, key):
"""根据key,获取工作表名称"""
try:
return self.conf.get(TABLE, key)
except:
log.error("输入table节点下的key,错误,请求察看配置文件~!!!")
raise KeyError("输入table节点下的key,错误,请求察看配置文件~!!!")
def get_sql_message(self, key):
"""根据key,获取数据库"""
try:
return self.conf.get(CONN_SQL, key)
except:
log.error("输入sql节点下的key,错误,请求察看配置文件~!!!")
raise KeyError("输入sql节点下的key,错误,请求察看配置文件~!!!")
if __name__ == '__main__':
ini = ReadIni()
print(ini.get_sql_message("host"))
# -*-coding:utf-8 -*- #
# ---------------------------------------------------------------------------
# ProjectName: test_57
# FileName: read_json.py
# Author: xxxxxxx
# Datetime: 2023/11/3 14:16
# Description:
#
# ---------------------------------------------------------------------------
import json
import os
from InterfaceAutoTest.common import log
def read_json(filename):
"""读取json文件,将json文件的内容转成python对象,并返回"""
if os.path.isfile(filename) and filename.endswith(".json"):
try:
with open(filename, mode="r", encoding="utf-8") as f:
return json.loads(f.read())
except:
log.error("开打json文件获取json文件的内容序列化为python对象失败,请察看json文件是否有错误!!!")
raise FileExistsError("开打json文件获取json文件的内容序列化为python对象失败,请察看json文件是否有错误!!!")
else:
log.error("json文件的路径不合法")
raise FileNotFoundError("json文件的路径不合法")
{
"认证接口":{
"登录系统":{
"LoginSuccess": {"password": "MTIzNDU2","username": "admin"},
"LoginErrorUsernameLong":{"password": "MTIzNDU2","username": "adminadminadminadminadminadmin"},
"LoginErrorUsernameShort":{"password": "MTIzNDU2","username": "a"},
"LoginErrorUsernameNone":{"password": "MTIzNDU2","username": ""},
"LoginErrorUsernameSpecial":{"password": "MTIzNDU2","username": "@#!@#!@"},
"LoginErrorPwdLong":{"password": "MTIzNDU2MTIzNDU2MTIzNDU2MTIzNDU2MTIzNDU2","username": "admin"},
"LoginErrorPwdShort":{"password": "m","username": "admin"},
"LoginErrorPwdNone":{"password": "","username": "admin"},
"LoginErrorPwdSpecial":{"password": "@#!@#!@","username": "admin"},
"LoginErrorPwdError":{"password": "MTIzNDU222","username": "admin"}
}
},
"维度管理": {
"添加维度": {
"AddDemSuccess": {
"code": "dem_test57_abc",
"description": "测试维度57",
"isDefault": 0,
"name": "测试57期的维度"
}
},
"根据维度编码获取维度信息": {
"GetDemMessageSuccess": {"code": "dem_test57_abc"}
},
"根据维度编码删除维度": {
"DeleteDemSuccess": {"ids": "不知道"}
}
},
"组织管理": {
"添加组织": {
"AddOrgSuccess": {
"code": "test_org_57",
"demId": "不知道",
"exceedLimitNum": 0,
"grade": "",
"limitNum": 0,
"name": "测试组织",
"nowNum": 0,
"orderNo": 0,
"parentId": "0"
}
},
"添加组织参数": {
"AddOrgParamsSuccess": {"query": {"orgCode": "test_org_57"}, "body": [{"alias":"sz","value":9000}]}
},
"删除组织": {
"DelOrgSuccess": "test_org_57"
}
}
}
[file]
;case为用例数据文件
case=case_data.json
;expect为期望数据文件
expect=expect_data.json
;excel为用例管理文件
excel=APIAutoTest.xlsx
;sql语句的json文件
sql=sql_data.json
[host]
;host为被测系统的域名
host=http://120.46.172.186:8080
[table]
;table_name为excel的工作表名称
table_name=BPM
[sql]
;链接数据库的配置
host=120.46.172.186
port=3306
user=root
pwd=root@2023
database=eipsaas
\ No newline at end of file
{
"认证接口":{
"登录系统":{
"LoginSuccess": {"username": "超级管理","account": "admin", "loginStatus": true},
"LoginErrorUsernameLong":{"state": false, "message":"账号或密码错误"},
"LoginErrorUsernameShort":{"state": false, "message":"账号或密码错误"},
"LoginErrorUsernameNone":{"state": false, "message":"账号或密码错误"},
"LoginErrorUsernameSpecial":{"state": false, "message":"账号或密码错误"},
"LoginErrorPwdLong":{"state": false, "message":"账号或密码错误"},
"LoginErrorPwdShort":{"state": false, "message":"账号或密码错误"},
"LoginErrorPwdNone":{"state": false, "message":"账号或密码错误"},
"LoginErrorPwdSpecial":{"state": false, "message":"账号或密码错误"},
"LoginErrorPwdError":{"state": false, "message":"账号或密码错误"}
},
"刷新token": {
"RefreshSuccess": {"message": "刷新成功"}
}
},
"维度管理": {
"添加维度": {
"AddDemSuccess": {"state": true, "message": "添加维度成功!"}
},
"根据维度编码获取维度信息": {
"GetDemMessageSuccess": {"demCode": "dem_test57_abc", "name": "测试57期的维度"}
},
"根据维度编码删除维度": {
"DeleteDemSuccess": {"state": true, "message": "删除维度成功"}
}
},
"组织管理": {
"添加组织": {
"AddOrgSuccess": {"state": true, "message": "添加组织成功!"}
},
"添加组织参数": {
"AddOrgParamsSuccess": {"state":true,"message":"保存组织参数成功!"}
},
"删除组织": {
"DelOrgSuccess": {"state":true,"message":"删除组织成功!"}
}
}
}
\ No newline at end of file
# -*-coding:utf-8 -*- #
# ---------------------------------------------------------------------------
# ProjectName: test_57
# FileName: settings.py
# Author: xxxxxxx
# Datetime: 2023/11/3 17:03
# Description:
#
# ---------------------------------------------------------------------------
# file节点名称====================
FILE = "file"
# file节点名称=key的名称===================
CASE = "case"
EXPECT = "expect"
EXCEL = "excel"
SQL = "sql"
# table节点名称========================
TABLE = "table"
# table节点名称=key的名称=======================
TABLE_NAME = "table_name"
# host节点名称=================
URL_HOST = "host"
# host节点名称=key的名称================
URL_HOST_CUSTOM = "host"
# sql节点名称==========================
CONN_SQL = "sql"
# sql节点名称=key的名称=========================
HOST = "host"
PORT = "port"
USER = "user"
PWD = "pwd"
DATABASE = "database"
# excel文件中的列号
NUMBER = "A"
MODULE = "B"
API = "C"
TITLE = "D"
LEVEL = "E"
URL = "G"
METHOD = "F"
MIME = "H"
CASE_DATA = "I"
EXPECT_DATA = "J"
SQL_TYPE = "K"
SQL_DATA = "L"
UPDATE_KEY = "M"
{
"维度管理": {
"添加维度": {
"AddDemSuccess": "DELETE FROM uc_demension WHERE `CODE_`=\"dem_test57_abc\";"
},
"根据维度编码删除维度": {
"DeleteDemSuccess": "SELECT ID_ from uc_demension WHERE `CODE_`=\"dem_test57_abc\";"
}
},
"组织管理": {
"添加组织": {
"AddOrgSuccess": {
"select": "SELECT ID_ from uc_demension WHERE `CODE_`=\"dem_test57_abc\";",
"delete": "DELETE FROM uc_org WHERE `CODE_`=\"test_org_57\";"
}
}
}
}
\ No newline at end of file
body {
font-family: Helvetica, Arial, sans-serif;
font-size: 12px;
/* do not increase min-width as some may use split screens */
min-width: 800px;
color: #999;
}
h1 {
font-size: 24px;
color: black;
}
h2 {
font-size: 16px;
color: black;
}
p {
color: black;
}
a {
color: #999;
}
table {
border-collapse: collapse;
}
/******************************
* SUMMARY INFORMATION
******************************/
#environment td {
padding: 5px;
border: 1px solid #e6e6e6;
vertical-align: top;
}
#environment tr:nth-child(odd) {
background-color: #f6f6f6;
}
#environment ul {
margin: 0;
padding: 0 20px;
}
/******************************
* TEST RESULT COLORS
******************************/
span.passed,
.passed .col-result {
color: green;
}
span.skipped,
span.xfailed,
span.rerun,
.skipped .col-result,
.xfailed .col-result,
.rerun .col-result {
color: orange;
}
span.error,
span.failed,
span.xpassed,
.error .col-result,
.failed .col-result,
.xpassed .col-result {
color: red;
}
.col-links__extra {
margin-right: 3px;
}
/******************************
* RESULTS TABLE
*
* 1. Table Layout
* 2. Extra
* 3. Sorting items
*
******************************/
/*------------------
* 1. Table Layout
*------------------*/
#results-table {
border: 1px solid #e6e6e6;
color: #999;
font-size: 12px;
width: 100%;
}
#results-table th,
#results-table td {
padding: 5px;
border: 1px solid #e6e6e6;
text-align: left;
}
#results-table th {
font-weight: bold;
}
/*------------------
* 2. Extra
*------------------*/
.logwrapper {
max-height: 230px;
overflow-y: scroll;
background-color: #e6e6e6;
}
.logwrapper.expanded {
max-height: none;
}
.logwrapper.expanded .logexpander:after {
content: "collapse [-]";
}
.logwrapper .logexpander {
z-index: 1;
position: sticky;
top: 10px;
width: max-content;
border: 1px solid;
border-radius: 3px;
padding: 5px 7px;
margin: 10px 0 10px calc(100% - 80px);
cursor: pointer;
background-color: #e6e6e6;
}
.logwrapper .logexpander:after {
content: "expand [+]";
}
.logwrapper .logexpander:hover {
color: #000;
border-color: #000;
}
.logwrapper .log {
min-height: 40px;
position: relative;
top: -50px;
height: calc(100% + 50px);
border: 1px solid #e6e6e6;
color: black;
display: block;
font-family: "Courier New", Courier, monospace;
padding: 5px;
padding-right: 80px;
white-space: pre-wrap;
}
div.media {
border: 1px solid #e6e6e6;
float: right;
height: 240px;
margin: 0 5px;
overflow: hidden;
width: 320px;
}
.media-container {
display: grid;
grid-template-columns: 25px auto 25px;
align-items: center;
flex: 1 1;
overflow: hidden;
height: 200px;
}
.media-container--fullscreen {
grid-template-columns: 0px auto 0px;
}
.media-container__nav--right,
.media-container__nav--left {
text-align: center;
cursor: pointer;
}
.media-container__viewport {
cursor: pointer;
text-align: center;
height: inherit;
}
.media-container__viewport img,
.media-container__viewport video {
object-fit: cover;
width: 100%;
max-height: 100%;
}
.media__name,
.media__counter {
display: flex;
flex-direction: row;
justify-content: space-around;
flex: 0 0 25px;
align-items: center;
}
.collapsible td:not(.col-links) {
cursor: pointer;
}
.collapsible td:not(.col-links):hover::after {
color: #bbb;
font-style: italic;
cursor: pointer;
}
.col-result {
width: 130px;
}
.col-result:hover::after {
content: " (hide details)";
}
.col-result.collapsed:hover::after {
content: " (show details)";
}
#environment-header h2:hover::after {
content: " (hide details)";
color: #bbb;
font-style: italic;
cursor: pointer;
font-size: 12px;
}
#environment-header.collapsed h2:hover::after {
content: " (show details)";
color: #bbb;
font-style: italic;
cursor: pointer;
font-size: 12px;
}
/*------------------
* 3. Sorting items
*------------------*/
.sortable {
cursor: pointer;
}
.sortable.desc:after {
content: " ";
position: relative;
left: 5px;
bottom: -12.5px;
border: 10px solid #4caf50;
border-bottom: 0;
border-left-color: transparent;
border-right-color: transparent;
}
.sortable.asc:after {
content: " ";
position: relative;
left: 5px;
bottom: 12.5px;
border: 10px solid #4caf50;
border-top: 0;
border-left-color: transparent;
border-right-color: transparent;
}
.hidden, .summary__reload__button.hidden {
display: none;
}
.summary__data {
flex: 0 0 550px;
}
.summary__reload {
flex: 1 1;
display: flex;
justify-content: center;
}
.summary__reload__button {
flex: 0 0 300px;
display: flex;
color: white;
font-weight: bold;
background-color: #4caf50;
text-align: center;
justify-content: center;
align-items: center;
border-radius: 3px;
cursor: pointer;
}
.summary__reload__button:hover {
background-color: #46a049;
}
.summary__spacer {
flex: 0 0 550px;
}
.controls {
display: flex;
justify-content: space-between;
}
.filters,
.collapse {
display: flex;
align-items: center;
}
.filters button,
.collapse button {
color: #999;
border: none;
background: none;
cursor: pointer;
text-decoration: underline;
}
.filters button:hover,
.collapse button:hover {
color: #ccc;
}
.filter__label {
margin-right: 10px;
}
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8"/>
<title id="head-title">test_zhangsan.html</title>
<link href="assets\style.css" rel="stylesheet" type="text/css"/>
</head>
<body>
<h1 id="title">test_zhangsan.html</h1>
<p>Report generated on 06-Nov-2023 at 11:49:05 by <a href="https://pypi.python.org/pypi/pytest-html">pytest-html</a>
v4.0.2</p>
<div id="environment-header">
<h2>Environment</h2>
</div>
<table id="environment"></table>
<!-- TEMPLATES -->
<template id="template_environment_row">
<tr>
<td></td>
<td></td>
</tr>
</template>
<template id="template_results-table__body--empty">
<tbody class="results-table-row">
<tr id="not-found-message">
<td colspan="4">No results found. Check the filters.</th>
</tr>
</template>
<template id="template_results-table__tbody">
<tbody class="results-table-row">
<tr class="collapsible">
</tr>
<tr class="extras-row">
<td class="extra" colspan="4">
<div class="extraHTML"></div>
<div class="media">
<div class="media-container">
<div class="media-container__nav--left"><</div>
<div class="media-container__viewport">
<img src="" />
<video controls>
<source src="" type="video/mp4">
</video>
</div>
<div class="media-container__nav--right">></div>
</div>
<div class="media__name"></div>
<div class="media__counter"></div>
</div>
<div class="logwrapper">
<div class="logexpander"></div>
<div class="log"></div>
</div>
</td>
</tr>
</tbody>
</template>
<!-- END TEMPLATES -->
<div class="summary">
<div class="summary__data">
<h2>Summary</h2>
<div class="additional-summary prefix">
</div>
<p class="run-count">17 tests took 00:00:02.</p>
<p class="filter">(Un)check the boxes to filter the results.</p>
<div class="summary__reload">
<div class="summary__reload__button hidden" onclick="location.reload()">
<div>There are still tests running. <br />Reload this page to ge the latest results!</div>
</div>
</div>
<div class="summary__spacer"></div>
<div class="controls">
<div class="filters">
<input checked="true" class="filter" name="filter_checkbox" type="checkbox" data-test-result="failed" />
<span class="failed">3 Failed,</span>
<input checked="true" class="filter" name="filter_checkbox" type="checkbox" data-test-result="passed" />
<span class="passed">14 Passed,</span>
<input checked="true" class="filter" name="filter_checkbox" type="checkbox" data-test-result="skipped" disabled/>
<span class="skipped">0 Skipped,</span>
<input checked="true" class="filter" name="filter_checkbox" type="checkbox" data-test-result="xfailed" disabled/>
<span class="xfailed">0 Expected failures,</span>
<input checked="true" class="filter" name="filter_checkbox" type="checkbox" data-test-result="xpassed" disabled/>
<span class="xpassed">0 Unexpected passes,</span>
<input checked="true" class="filter" name="filter_checkbox" type="checkbox" data-test-result="error" disabled/>
<span class="error">0 Errors,</span>
<input checked="true" class="filter" name="filter_checkbox" type="checkbox" data-test-result="rerun" disabled/>
<span class="rerun">0 Reruns</span>
</div>
<div class="collapse">
<button id="show_all_details">Show all details</button>&nbsp;/&nbsp;<button id="hide_all_details">Hide all details</button>
</div>
</div>
</div>
<div class="additional-summary summary">
</div>
<div class="additional-summary postfix">
</div>
</div>
<table id="results-table">
<thead id="results-table-head">
<tr>
<th class="sortable" data-column-type="result">Result</th>
<th class="sortable" data-column-type="testId">Test</th>
<th class="sortable" data-column-type="duration">Duration</th>
<th>Links</th>
</tr>
</thead>
</table>
</body>
<footer>
<div id="data-container" data-jsonblob="{&#34;environment&#34;: {&#34;Python&#34;: &#34;3.8.10&#34;, &#34;Platform&#34;: &#34;Windows-10-10.0.22621-SP0&#34;, &#34;Packages&#34;: {&#34;pytest&#34;: &#34;7.4.3&#34;, &#34;pluggy&#34;: &#34;1.3.0&#34;}, &#34;Plugins&#34;: {&#34;allure-pytest&#34;: &#34;2.13.2&#34;, &#34;Faker&#34;: &#34;19.6.2&#34;, &#34;dependency&#34;: &#34;0.5.1&#34;, &#34;html&#34;: &#34;4.0.2&#34;, &#34;metadata&#34;: &#34;3.0.0&#34;, &#34;ordering&#34;: &#34;0.6&#34;, &#34;rerunfailures&#34;: &#34;12.0&#34;}, &#34;JAVA_HOME&#34;: &#34;C:\\Program Files\\Java\\jdk1.8.0_251&#34;}, &#34;tests&#34;: {&#34;test_zhangsan/test_bpm.py::TestBPM::test_bpm[\u8ba4\u8bc1\u63a5\u53e3-\u767b\u5f55\u7cfb\u7edf-\u6b63\u5411\u7528\u4f8b-username\u548cpassword\u6b63\u786e-\u9ad8-http://120.46.172.186:8080/auth-POST-json-case_data0-expect_data0-None-None-None]&#34;: [{&#34;extras&#34;: [], &#34;result&#34;: &#34;Failed&#34;, &#34;testId&#34;: &#34;test_zhangsan/test_bpm.py::TestBPM::test_bpm[\u8ba4\u8bc1\u63a5\u53e3-\u767b\u5f55\u7cfb\u7edf-\u6b63\u5411\u7528\u4f8b-username\u548cpassword\u6b63\u786e-\u9ad8-http://120.46.172.186:8080/auth-POST-json-case_data0-expect_data0-None-None-None]&#34;, &#34;duration&#34;: &#34;56 ms&#34;, &#34;resultsTableRow&#34;: [&#34;&lt;td class=\&#34;col-result\&#34;&gt;Failed&lt;/td&gt;&#34;, &#34;&lt;td class=\&#34;col-testId\&#34;&gt;test_zhangsan/test_bpm.py::TestBPM::test_bpm[\u8ba4\u8bc1\u63a5\u53e3-\u767b\u5f55\u7cfb\u7edf-\u6b63\u5411\u7528\u4f8b-username\u548cpassword\u6b63\u786e-\u9ad8-http://120.46.172.186:8080/auth-POST-json-case_data0-expect_data0-None-None-None]&lt;/td&gt;&#34;, &#34;&lt;td class=\&#34;col-duration\&#34;&gt;56 ms&lt;/td&gt;&#34;, &#34;&lt;td class=\&#34;col-links\&#34;&gt;&lt;/td&gt;&#34;], &#34;log&#34;: &#34;self = &amp;lt;InterfaceAutoTest.test_case.test_zhangsan.test_bpm.TestBPM object at 0x0000018FED2C55E0&amp;gt;\ndb_fix = &amp;lt;InterfaceAutoTest.common.db.DB object at 0x0000018FED3215B0&amp;gt;\nreq_fix = &amp;lt;InterfaceAutoTest.requests_method.requests_method.RequestsMethod object at 0x0000018FED36BD00&amp;gt;\nmodule_name = &#39;\u8ba4\u8bc1\u63a5\u53e3&#39;, api_name = &#39;\u767b\u5f55\u7cfb\u7edf&#39;, title = &#39;\u6b63\u5411\u7528\u4f8b-username\u548cpassword\u6b63\u786e&#39;\nlevel = &#39;\u9ad8&#39;, case_url = &#39;http://120.46.172.186:8080/auth&#39;, case_method = &#39;POST&#39;\ncase_mime = &#39;json&#39;, case_data = {&#39;password&#39;: &#39;MTIzNDU2&#39;, &#39;username&#39;: &#39;admin&#39;}\nexpect_data = {&#39;account&#39;: &#39;admin&#39;, &#39;loginStatus&#39;: True, &#39;username&#39;: &#39;\u8d85\u7ea7\u7ba1\u7406&#39;}\nsql_type = None, sql_data = None, update_key = None\n\n @allure.epic(\&#34;BPM_\u5f20\u4e09\&#34;)\n @pytest.mark.parametrize(\&#34;module_name, api_name, title, level, case_url, case_method, case_mime, case_data, expect_data, sql_type, sql_data, update_key\&#34;, ReadExcel(\&#34;BPM\&#34;, excel_path=excel_path).get_data())\n def test_bpm(self, db_fix, req_fix, module_name, api_name, title, level, case_url, case_method, case_mime, case_data, expect_data, sql_type, sql_data, update_key):\n allure.dynamic.feature(module_name)\n allure.dynamic.story(api_name)\n allure.dynamic.title(title)\n allure.dynamic.severity(level)\n # \u5224\u65adsql\u8bed\u53e5\u7684\u7c7b\u578b\u662f\u5426\u4e3adelete\n if sql_type == \&#34;delete\&#34;:\n # \u4f7f\u7528DB\u7c7b\u5bf9\u8c61\u6267\u884c\u5220\u9664\u7684sql\u8bed\u53e5\n db_fix.delete(sql_data)\n # \u4f7f\u7528RequestsMethod\u7c7b\u5bf9\u8c61\u53d1\u9001\u8bf7\u6c42--pass\n # \u5224\u65adsql\u8bed\u53e5\u7c7b\u578b\u662f\u5426\u4e3aselect\n elif sql_type == \&#34;select\&#34;:\n # \u4f7f\u7528DB\u7c7b\u5bf9\u8c61\u6267\u884c\u67e5\u8be2\u7684sql\u8bed\u53e5\uff0c\u5e76\u63a5\u6536\u67e5\u8be2\u7684\u7ed3\u679c\n select_result = db_fix.select(sql_data)\n # \u5c06\u67e5\u8be2\u7ed3\u679c\u66f4\u65b0\u5230\u7528\u4f8b\u6570\u636e\u4e2d\n case_data[update_key] = select_result\n # \u4f7f\u7528RequestsMethod\u7c7b\u5bf9\u8c61\u53d1\u9001\u8bf7\u6c42--pass\n \n # \u5224\u65adsql\u8bed\u53e5\u7684\u7c7b\u578b\u662f\u5426\u4e3aselect|delete\u6216\u8005\u4e3adelete|select\n elif sql_type == \&#34;select|delete\&#34; or sql_type == \&#34;delete|select\&#34;:\n # \u4f7f\u7528DB\u7c7b\u5bf9\u8c61\u6267\u884c\u5220\u9664\u7684sql\u8bed\u53e5\n db_fix.delete(sql_data.get(\&#34;delete\&#34;))\n # \u4f7f\u7528DB\u7c7b\u5bf9\u8c61\u6267\u884c\u67e5\u8be2\u7684sql\u8bed\u53e5\uff0c\u5e76\u63a5\u6536\u67e5\u8be2\u7684\u7ed3\u679c\n select_result = db_fix.select(sql_data.get(\&#34;select\&#34;))\n # \u5c06\u67e5\u8be2\u7ed3\u679c\u66f4\u65b0\u5230\u7528\u4f8b\u6570\u636e\u4e2d\n case_data[update_key] = select_result\n \n # \u4f7f\u7528RequestsMethod\u7c7b\u5bf9\u8c61\u53d1\u9001\u8bf7\u6c42\n res = req_fix.request_all(req_method=case_method, req_url=case_url, req_mime=case_mime, case_data=case_data)\n \n \n # \u65ad\u8a00\n try:\n for key in expect_data:\n&amp;gt; assert expect_data[key] == res.json().get(key)\nE AssertionError: assert &#39;\u8d85\u7ea7\u7ba1\u7406&#39; == &#39;\u8d85\u7ea7\u7ba1\u7406\u5458&#39;\nE - \u8d85\u7ea7\u7ba1\u7406\u5458\nE ? -\nE + \u8d85\u7ea7\u7ba1\u7406\n\ntest_zhangsan\\test_bpm.py:57: AssertionError\n\nDuring handling of the above exception, another exception occurred:\n\nself = &amp;lt;InterfaceAutoTest.test_case.test_zhangsan.test_bpm.TestBPM object at 0x0000018FED2C55E0&amp;gt;\ndb_fix = &amp;lt;InterfaceAutoTest.common.db.DB object at 0x0000018FED3215B0&amp;gt;\nreq_fix = &amp;lt;InterfaceAutoTest.requests_method.requests_method.RequestsMethod object at 0x0000018FED36BD00&amp;gt;\nmodule_name = &#39;\u8ba4\u8bc1\u63a5\u53e3&#39;, api_name = &#39;\u767b\u5f55\u7cfb\u7edf&#39;, title = &#39;\u6b63\u5411\u7528\u4f8b-username\u548cpassword\u6b63\u786e&#39;\nlevel = &#39;\u9ad8&#39;, case_url = &#39;http://120.46.172.186:8080/auth&#39;, case_method = &#39;POST&#39;\ncase_mime = &#39;json&#39;, case_data = {&#39;password&#39;: &#39;MTIzNDU2&#39;, &#39;username&#39;: &#39;admin&#39;}\nexpect_data = {&#39;account&#39;: &#39;admin&#39;, &#39;loginStatus&#39;: True, &#39;username&#39;: &#39;\u8d85\u7ea7\u7ba1\u7406&#39;}\nsql_type = None, sql_data = None, update_key = None\n\n @allure.epic(\&#34;BPM_\u5f20\u4e09\&#34;)\n @pytest.mark.parametrize(\&#34;module_name, api_name, title, level, case_url, case_method, case_mime, case_data, expect_data, sql_type, sql_data, update_key\&#34;, ReadExcel(\&#34;BPM\&#34;, excel_path=excel_path).get_data())\n def test_bpm(self, db_fix, req_fix, module_name, api_name, title, level, case_url, case_method, case_mime, case_data, expect_data, sql_type, sql_data, update_key):\n allure.dynamic.feature(module_name)\n allure.dynamic.story(api_name)\n allure.dynamic.title(title)\n allure.dynamic.severity(level)\n # \u5224\u65adsql\u8bed\u53e5\u7684\u7c7b\u578b\u662f\u5426\u4e3adelete\n if sql_type == \&#34;delete\&#34;:\n # \u4f7f\u7528DB\u7c7b\u5bf9\u8c61\u6267\u884c\u5220\u9664\u7684sql\u8bed\u53e5\n db_fix.delete(sql_data)\n # \u4f7f\u7528RequestsMethod\u7c7b\u5bf9\u8c61\u53d1\u9001\u8bf7\u6c42--pass\n # \u5224\u65adsql\u8bed\u53e5\u7c7b\u578b\u662f\u5426\u4e3aselect\n elif sql_type == \&#34;select\&#34;:\n # \u4f7f\u7528DB\u7c7b\u5bf9\u8c61\u6267\u884c\u67e5\u8be2\u7684sql\u8bed\u53e5\uff0c\u5e76\u63a5\u6536\u67e5\u8be2\u7684\u7ed3\u679c\n select_result = db_fix.select(sql_data)\n # \u5c06\u67e5\u8be2\u7ed3\u679c\u66f4\u65b0\u5230\u7528\u4f8b\u6570\u636e\u4e2d\n case_data[update_key] = select_result\n # \u4f7f\u7528RequestsMethod\u7c7b\u5bf9\u8c61\u53d1\u9001\u8bf7\u6c42--pass\n \n # \u5224\u65adsql\u8bed\u53e5\u7684\u7c7b\u578b\u662f\u5426\u4e3aselect|delete\u6216\u8005\u4e3adelete|select\n elif sql_type == \&#34;select|delete\&#34; or sql_type == \&#34;delete|select\&#34;:\n # \u4f7f\u7528DB\u7c7b\u5bf9\u8c61\u6267\u884c\u5220\u9664\u7684sql\u8bed\u53e5\n db_fix.delete(sql_data.get(\&#34;delete\&#34;))\n # \u4f7f\u7528DB\u7c7b\u5bf9\u8c61\u6267\u884c\u67e5\u8be2\u7684sql\u8bed\u53e5\uff0c\u5e76\u63a5\u6536\u67e5\u8be2\u7684\u7ed3\u679c\n select_result = db_fix.select(sql_data.get(\&#34;select\&#34;))\n # \u5c06\u67e5\u8be2\u7ed3\u679c\u66f4\u65b0\u5230\u7528\u4f8b\u6570\u636e\u4e2d\n case_data[update_key] = select_result\n \n # \u4f7f\u7528RequestsMethod\u7c7b\u5bf9\u8c61\u53d1\u9001\u8bf7\u6c42\n res = req_fix.request_all(req_method=case_method, req_url=case_url, req_mime=case_mime, case_data=case_data)\n \n \n # \u65ad\u8a00\n try:\n for key in expect_data:\n assert expect_data[key] == res.json().get(key)\n except:\n log.error(\&#34;\u65ad\u8a00\u5931\u8d25\&#34;+\&#34;\uff0c\u7528\u4f8b\u6570\u636e\u4e3a\uff1a\&#34;+str(case_data)+\&#34;,\u671f\u671b\u6570\u636e\u4e3a\uff1a\&#34;+str(expect_data)+\&#34;,\u670d\u52a1\u5668\u8fd4\u56de\u7684\u6570\u636e\u4e3a\uff1a\&#34;+res.text)\n&amp;gt; raise AssertionError(\&#34;\u65ad\u8a00\u5931\u8d25\&#34;)\nE AssertionError: \u65ad\u8a00\u5931\u8d25\n\ntest_zhangsan\\test_bpm.py:60: AssertionError\n\n------------------------------ Captured log call -------------------------------\nERROR \u9ec4\u603b:test_bpm.py:59 \u65ad\u8a00\u5931\u8d25\uff0c\u7528\u4f8b\u6570\u636e\u4e3a\uff1a{&#39;password&#39;: &#39;MTIzNDU2&#39;, &#39;username&#39;: &#39;admin&#39;},\u671f\u671b\u6570\u636e\u4e3a\uff1a{&#39;username&#39;: &#39;\u8d85\u7ea7\u7ba1\u7406&#39;, &#39;account&#39;: &#39;admin&#39;, &#39;loginStatus&#39;: True},\u670d\u52a1\u5668\u8fd4\u56de\u7684\u6570\u636e\u4e3a\uff1a{\&#34;token\&#34;:\&#34;eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiJhZG1pbiIsInRlbmFudElkIjoiLTEiLCJleHAiOjE2OTkzMjg5NDQsImlhdCI6MTY5OTI0MjU0NH0.4y6er6hXCfF3A27H0Cci7p6zvL6fALMilj_xBfIxVhMU8ddr0COMKC6HI4GNR3Yo0f9AyJz8n-uzQi8bYjEPVA\&#34;,\&#34;username\&#34;:\&#34;\u8d85\u7ea7\u7ba1\u7406\u5458\&#34;,\&#34;account\&#34;:\&#34;admin\&#34;,\&#34;userId\&#34;:\&#34;1\&#34;,\&#34;expiration\&#34;:86400,\&#34;loginStatus\&#34;:true,\&#34;userAttrs\&#34;:{\&#34;tenantId\&#34;:\&#34;-1\&#34;}}\n\n&#34;}], &#34;test_zhangsan/test_bpm.py::TestBPM::test_bpm[\u8ba4\u8bc1\u63a5\u53e3-\u767b\u5f55\u7cfb\u7edf-\u53cd\u5411\u7528\u4f8b-username\u8fc7\u957f-password\u6b63\u786e-\u4e2d-http://120.46.172.186:8080/auth-POST-json-case_data1-expect_data1-None-None-None]&#34;: [{&#34;extras&#34;: [], &#34;result&#34;: &#34;Passed&#34;, &#34;testId&#34;: &#34;test_zhangsan/test_bpm.py::TestBPM::test_bpm[\u8ba4\u8bc1\u63a5\u53e3-\u767b\u5f55\u7cfb\u7edf-\u53cd\u5411\u7528\u4f8b-username\u8fc7\u957f-password\u6b63\u786e-\u4e2d-http://120.46.172.186:8080/auth-POST-json-case_data1-expect_data1-None-None-None]&#34;, &#34;duration&#34;: &#34;52 ms&#34;, &#34;resultsTableRow&#34;: [&#34;&lt;td class=\&#34;col-result\&#34;&gt;Passed&lt;/td&gt;&#34;, &#34;&lt;td class=\&#34;col-testId\&#34;&gt;test_zhangsan/test_bpm.py::TestBPM::test_bpm[\u8ba4\u8bc1\u63a5\u53e3-\u767b\u5f55\u7cfb\u7edf-\u53cd\u5411\u7528\u4f8b-username\u8fc7\u957f-password\u6b63\u786e-\u4e2d-http://120.46.172.186:8080/auth-POST-json-case_data1-expect_data1-None-None-None]&lt;/td&gt;&#34;, &#34;&lt;td class=\&#34;col-duration\&#34;&gt;52 ms&lt;/td&gt;&#34;, &#34;&lt;td class=\&#34;col-links\&#34;&gt;&lt;/td&gt;&#34;], &#34;log&#34;: &#34;No log output captured.&#34;}], &#34;test_zhangsan/test_bpm.py::TestBPM::test_bpm[\u8ba4\u8bc1\u63a5\u53e3-\u767b\u5f55\u7cfb\u7edf-\u53cd\u5411\u7528\u4f8b-username\u8fc7\u77ed-password\u6b63\u786e-\u4e2d-http://120.46.172.186:8080/auth-POST-json-case_data2-expect_data2-None-None-None]&#34;: [{&#34;extras&#34;: [], &#34;result&#34;: &#34;Passed&#34;, &#34;testId&#34;: &#34;test_zhangsan/test_bpm.py::TestBPM::test_bpm[\u8ba4\u8bc1\u63a5\u53e3-\u767b\u5f55\u7cfb\u7edf-\u53cd\u5411\u7528\u4f8b-username\u8fc7\u77ed-password\u6b63\u786e-\u4e2d-http://120.46.172.186:8080/auth-POST-json-case_data2-expect_data2-None-None-None]&#34;, &#34;duration&#34;: &#34;91 ms&#34;, &#34;resultsTableRow&#34;: [&#34;&lt;td class=\&#34;col-result\&#34;&gt;Passed&lt;/td&gt;&#34;, &#34;&lt;td class=\&#34;col-testId\&#34;&gt;test_zhangsan/test_bpm.py::TestBPM::test_bpm[\u8ba4\u8bc1\u63a5\u53e3-\u767b\u5f55\u7cfb\u7edf-\u53cd\u5411\u7528\u4f8b-username\u8fc7\u77ed-password\u6b63\u786e-\u4e2d-http://120.46.172.186:8080/auth-POST-json-case_data2-expect_data2-None-None-None]&lt;/td&gt;&#34;, &#34;&lt;td class=\&#34;col-duration\&#34;&gt;91 ms&lt;/td&gt;&#34;, &#34;&lt;td class=\&#34;col-links\&#34;&gt;&lt;/td&gt;&#34;], &#34;log&#34;: &#34;No log output captured.&#34;}], &#34;test_zhangsan/test_bpm.py::TestBPM::test_bpm[\u8ba4\u8bc1\u63a5\u53e3-\u767b\u5f55\u7cfb\u7edf-\u53cd\u5411\u7528\u4f8b-username\u4e3a\u7a7a-password\u6b63\u786e-\u4e2d-http://120.46.172.186:8080/auth-POST-json-case_data3-expect_data3-None-None-None]&#34;: [{&#34;extras&#34;: [], &#34;result&#34;: &#34;Passed&#34;, &#34;testId&#34;: &#34;test_zhangsan/test_bpm.py::TestBPM::test_bpm[\u8ba4\u8bc1\u63a5\u53e3-\u767b\u5f55\u7cfb\u7edf-\u53cd\u5411\u7528\u4f8b-username\u4e3a\u7a7a-password\u6b63\u786e-\u4e2d-http://120.46.172.186:8080/auth-POST-json-case_data3-expect_data3-None-None-None]&#34;, &#34;duration&#34;: &#34;90 ms&#34;, &#34;resultsTableRow&#34;: [&#34;&lt;td class=\&#34;col-result\&#34;&gt;Passed&lt;/td&gt;&#34;, &#34;&lt;td class=\&#34;col-testId\&#34;&gt;test_zhangsan/test_bpm.py::TestBPM::test_bpm[\u8ba4\u8bc1\u63a5\u53e3-\u767b\u5f55\u7cfb\u7edf-\u53cd\u5411\u7528\u4f8b-username\u4e3a\u7a7a-password\u6b63\u786e-\u4e2d-http://120.46.172.186:8080/auth-POST-json-case_data3-expect_data3-None-None-None]&lt;/td&gt;&#34;, &#34;&lt;td class=\&#34;col-duration\&#34;&gt;90 ms&lt;/td&gt;&#34;, &#34;&lt;td class=\&#34;col-links\&#34;&gt;&lt;/td&gt;&#34;], &#34;log&#34;: &#34;No log output captured.&#34;}], &#34;test_zhangsan/test_bpm.py::TestBPM::test_bpm[\u8ba4\u8bc1\u63a5\u53e3-\u767b\u5f55\u7cfb\u7edf-\u53cd\u5411\u7528\u4f8b-username\u4e3a\u7279\u6b8a\u5b57\u7b26-password\u6b63\u786e-\u4e2d-http://120.46.172.186:8080/auth-POST-json-case_data4-expect_data4-None-None-None]&#34;: [{&#34;extras&#34;: [], &#34;result&#34;: &#34;Passed&#34;, &#34;testId&#34;: &#34;test_zhangsan/test_bpm.py::TestBPM::test_bpm[\u8ba4\u8bc1\u63a5\u53e3-\u767b\u5f55\u7cfb\u7edf-\u53cd\u5411\u7528\u4f8b-username\u4e3a\u7279\u6b8a\u5b57\u7b26-password\u6b63\u786e-\u4e2d-http://120.46.172.186:8080/auth-POST-json-case_data4-expect_data4-None-None-None]&#34;, &#34;duration&#34;: &#34;87 ms&#34;, &#34;resultsTableRow&#34;: [&#34;&lt;td class=\&#34;col-result\&#34;&gt;Passed&lt;/td&gt;&#34;, &#34;&lt;td class=\&#34;col-testId\&#34;&gt;test_zhangsan/test_bpm.py::TestBPM::test_bpm[\u8ba4\u8bc1\u63a5\u53e3-\u767b\u5f55\u7cfb\u7edf-\u53cd\u5411\u7528\u4f8b-username\u4e3a\u7279\u6b8a\u5b57\u7b26-password\u6b63\u786e-\u4e2d-http://120.46.172.186:8080/auth-POST-json-case_data4-expect_data4-None-None-None]&lt;/td&gt;&#34;, &#34;&lt;td class=\&#34;col-duration\&#34;&gt;87 ms&lt;/td&gt;&#34;, &#34;&lt;td class=\&#34;col-links\&#34;&gt;&lt;/td&gt;&#34;], &#34;log&#34;: &#34;No log output captured.&#34;}], &#34;test_zhangsan/test_bpm.py::TestBPM::test_bpm[\u8ba4\u8bc1\u63a5\u53e3-\u767b\u5f55\u7cfb\u7edf-\u53cd\u5411\u7528\u4f8b-password\u8fc7\u957f-username\u6b63\u786e-\u4e2d-http://120.46.172.186:8080/auth-POST-application/json-case_data5-expect_data5-None-None-None]&#34;: [{&#34;extras&#34;: [], &#34;result&#34;: &#34;Passed&#34;, &#34;testId&#34;: &#34;test_zhangsan/test_bpm.py::TestBPM::test_bpm[\u8ba4\u8bc1\u63a5\u53e3-\u767b\u5f55\u7cfb\u7edf-\u53cd\u5411\u7528\u4f8b-password\u8fc7\u957f-username\u6b63\u786e-\u4e2d-http://120.46.172.186:8080/auth-POST-application/json-case_data5-expect_data5-None-None-None]&#34;, &#34;duration&#34;: &#34;94 ms&#34;, &#34;resultsTableRow&#34;: [&#34;&lt;td class=\&#34;col-result\&#34;&gt;Passed&lt;/td&gt;&#34;, &#34;&lt;td class=\&#34;col-testId\&#34;&gt;test_zhangsan/test_bpm.py::TestBPM::test_bpm[\u8ba4\u8bc1\u63a5\u53e3-\u767b\u5f55\u7cfb\u7edf-\u53cd\u5411\u7528\u4f8b-password\u8fc7\u957f-username\u6b63\u786e-\u4e2d-http://120.46.172.186:8080/auth-POST-application/json-case_data5-expect_data5-None-None-None]&lt;/td&gt;&#34;, &#34;&lt;td class=\&#34;col-duration\&#34;&gt;94 ms&lt;/td&gt;&#34;, &#34;&lt;td class=\&#34;col-links\&#34;&gt;&lt;/td&gt;&#34;], &#34;log&#34;: &#34;No log output captured.&#34;}], &#34;test_zhangsan/test_bpm.py::TestBPM::test_bpm[\u8ba4\u8bc1\u63a5\u53e3-\u767b\u5f55\u7cfb\u7edf-\u53cd\u5411\u7528\u4f8b-password\u8fc7\u77ed-username\u6b63\u786e-\u4e2d-http://120.46.172.186:8080/auth-POST-application/json-case_data6-expect_data6-None-None-None]&#34;: [{&#34;extras&#34;: [], &#34;result&#34;: &#34;Passed&#34;, &#34;testId&#34;: &#34;test_zhangsan/test_bpm.py::TestBPM::test_bpm[\u8ba4\u8bc1\u63a5\u53e3-\u767b\u5f55\u7cfb\u7edf-\u53cd\u5411\u7528\u4f8b-password\u8fc7\u77ed-username\u6b63\u786e-\u4e2d-http://120.46.172.186:8080/auth-POST-application/json-case_data6-expect_data6-None-None-None]&#34;, &#34;duration&#34;: &#34;95 ms&#34;, &#34;resultsTableRow&#34;: [&#34;&lt;td class=\&#34;col-result\&#34;&gt;Passed&lt;/td&gt;&#34;, &#34;&lt;td class=\&#34;col-testId\&#34;&gt;test_zhangsan/test_bpm.py::TestBPM::test_bpm[\u8ba4\u8bc1\u63a5\u53e3-\u767b\u5f55\u7cfb\u7edf-\u53cd\u5411\u7528\u4f8b-password\u8fc7\u77ed-username\u6b63\u786e-\u4e2d-http://120.46.172.186:8080/auth-POST-application/json-case_data6-expect_data6-None-None-None]&lt;/td&gt;&#34;, &#34;&lt;td class=\&#34;col-duration\&#34;&gt;95 ms&lt;/td&gt;&#34;, &#34;&lt;td class=\&#34;col-links\&#34;&gt;&lt;/td&gt;&#34;], &#34;log&#34;: &#34;No log output captured.&#34;}], &#34;test_zhangsan/test_bpm.py::TestBPM::test_bpm[\u8ba4\u8bc1\u63a5\u53e3-\u767b\u5f55\u7cfb\u7edf-\u53cd\u5411\u7528\u4f8b-password\u4e3a\u7a7a-username\u6b63\u786e-\u4e2d-http://120.46.172.186:8080/auth-POST-json-case_data7-expect_data7-None-None-None]&#34;: [{&#34;extras&#34;: [], &#34;result&#34;: &#34;Passed&#34;, &#34;testId&#34;: &#34;test_zhangsan/test_bpm.py::TestBPM::test_bpm[\u8ba4\u8bc1\u63a5\u53e3-\u767b\u5f55\u7cfb\u7edf-\u53cd\u5411\u7528\u4f8b-password\u4e3a\u7a7a-username\u6b63\u786e-\u4e2d-http://120.46.172.186:8080/auth-POST-json-case_data7-expect_data7-None-None-None]&#34;, &#34;duration&#34;: &#34;93 ms&#34;, &#34;resultsTableRow&#34;: [&#34;&lt;td class=\&#34;col-result\&#34;&gt;Passed&lt;/td&gt;&#34;, &#34;&lt;td class=\&#34;col-testId\&#34;&gt;test_zhangsan/test_bpm.py::TestBPM::test_bpm[\u8ba4\u8bc1\u63a5\u53e3-\u767b\u5f55\u7cfb\u7edf-\u53cd\u5411\u7528\u4f8b-password\u4e3a\u7a7a-username\u6b63\u786e-\u4e2d-http://120.46.172.186:8080/auth-POST-json-case_data7-expect_data7-None-None-None]&lt;/td&gt;&#34;, &#34;&lt;td class=\&#34;col-duration\&#34;&gt;93 ms&lt;/td&gt;&#34;, &#34;&lt;td class=\&#34;col-links\&#34;&gt;&lt;/td&gt;&#34;], &#34;log&#34;: &#34;No log output captured.&#34;}], &#34;test_zhangsan/test_bpm.py::TestBPM::test_bpm[\u8ba4\u8bc1\u63a5\u53e3-\u767b\u5f55\u7cfb\u7edf-\u53cd\u5411\u7528\u4f8b-password\u7279\u6b8a\u5b57\u7b26-username\u6b63\u786e-\u4e2d-http://120.46.172.186:8080/auth-POST-application/json-case_data8-expect_data8-None-None-None]&#34;: [{&#34;extras&#34;: [], &#34;result&#34;: &#34;Passed&#34;, &#34;testId&#34;: &#34;test_zhangsan/test_bpm.py::TestBPM::test_bpm[\u8ba4\u8bc1\u63a5\u53e3-\u767b\u5f55\u7cfb\u7edf-\u53cd\u5411\u7528\u4f8b-password\u7279\u6b8a\u5b57\u7b26-username\u6b63\u786e-\u4e2d-http://120.46.172.186:8080/auth-POST-application/json-case_data8-expect_data8-None-None-None]&#34;, &#34;duration&#34;: &#34;92 ms&#34;, &#34;resultsTableRow&#34;: [&#34;&lt;td class=\&#34;col-result\&#34;&gt;Passed&lt;/td&gt;&#34;, &#34;&lt;td class=\&#34;col-testId\&#34;&gt;test_zhangsan/test_bpm.py::TestBPM::test_bpm[\u8ba4\u8bc1\u63a5\u53e3-\u767b\u5f55\u7cfb\u7edf-\u53cd\u5411\u7528\u4f8b-password\u7279\u6b8a\u5b57\u7b26-username\u6b63\u786e-\u4e2d-http://120.46.172.186:8080/auth-POST-application/json-case_data8-expect_data8-None-None-None]&lt;/td&gt;&#34;, &#34;&lt;td class=\&#34;col-duration\&#34;&gt;92 ms&lt;/td&gt;&#34;, &#34;&lt;td class=\&#34;col-links\&#34;&gt;&lt;/td&gt;&#34;], &#34;log&#34;: &#34;No log output captured.&#34;}], &#34;test_zhangsan/test_bpm.py::TestBPM::test_bpm[\u8ba4\u8bc1\u63a5\u53e3-\u767b\u5f55\u7cfb\u7edf-\u53cd\u5411\u7528\u4f8b-password\u9519\u8bef-username\u6b63\u786e-\u4e2d-http://120.46.172.186:8080/auth-POST-json-case_data9-expect_data9-None-None-None]&#34;: [{&#34;extras&#34;: [], &#34;result&#34;: &#34;Passed&#34;, &#34;testId&#34;: &#34;test_zhangsan/test_bpm.py::TestBPM::test_bpm[\u8ba4\u8bc1\u63a5\u53e3-\u767b\u5f55\u7cfb\u7edf-\u53cd\u5411\u7528\u4f8b-password\u9519\u8bef-username\u6b63\u786e-\u4e2d-http://120.46.172.186:8080/auth-POST-json-case_data9-expect_data9-None-None-None]&#34;, &#34;duration&#34;: &#34;90 ms&#34;, &#34;resultsTableRow&#34;: [&#34;&lt;td class=\&#34;col-result\&#34;&gt;Passed&lt;/td&gt;&#34;, &#34;&lt;td class=\&#34;col-testId\&#34;&gt;test_zhangsan/test_bpm.py::TestBPM::test_bpm[\u8ba4\u8bc1\u63a5\u53e3-\u767b\u5f55\u7cfb\u7edf-\u53cd\u5411\u7528\u4f8b-password\u9519\u8bef-username\u6b63\u786e-\u4e2d-http://120.46.172.186:8080/auth-POST-json-case_data9-expect_data9-None-None-None]&lt;/td&gt;&#34;, &#34;&lt;td class=\&#34;col-duration\&#34;&gt;90 ms&lt;/td&gt;&#34;, &#34;&lt;td class=\&#34;col-links\&#34;&gt;&lt;/td&gt;&#34;], &#34;log&#34;: &#34;No log output captured.&#34;}], &#34;test_zhangsan/test_bpm.py::TestBPM::test_bpm[\u8ba4\u8bc1\u63a5\u53e3-\u5237\u65b0token-\u6b63\u5411\u7528\u4f8b-\u4e2d-http://120.46.172.186:8080/refresh-GET-None-None-expect_data10-None-None-None]&#34;: [{&#34;extras&#34;: [], &#34;result&#34;: &#34;Failed&#34;, &#34;testId&#34;: &#34;test_zhangsan/test_bpm.py::TestBPM::test_bpm[\u8ba4\u8bc1\u63a5\u53e3-\u5237\u65b0token-\u6b63\u5411\u7528\u4f8b-\u4e2d-http://120.46.172.186:8080/refresh-GET-None-None-expect_data10-None-None-None]&#34;, &#34;duration&#34;: &#34;96 ms&#34;, &#34;resultsTableRow&#34;: [&#34;&lt;td class=\&#34;col-result\&#34;&gt;Failed&lt;/td&gt;&#34;, &#34;&lt;td class=\&#34;col-testId\&#34;&gt;test_zhangsan/test_bpm.py::TestBPM::test_bpm[\u8ba4\u8bc1\u63a5\u53e3-\u5237\u65b0token-\u6b63\u5411\u7528\u4f8b-\u4e2d-http://120.46.172.186:8080/refresh-GET-None-None-expect_data10-None-None-None]&lt;/td&gt;&#34;, &#34;&lt;td class=\&#34;col-duration\&#34;&gt;96 ms&lt;/td&gt;&#34;, &#34;&lt;td class=\&#34;col-links\&#34;&gt;&lt;/td&gt;&#34;], &#34;log&#34;: &#34;self = &amp;lt;InterfaceAutoTest.test_case.test_zhangsan.test_bpm.TestBPM object at 0x0000018FED2DC970&amp;gt;\ndb_fix = &amp;lt;InterfaceAutoTest.common.db.DB object at 0x0000018FED3215B0&amp;gt;\nreq_fix = &amp;lt;InterfaceAutoTest.requests_method.requests_method.RequestsMethod object at 0x0000018FED36BD00&amp;gt;\nmodule_name = &#39;\u8ba4\u8bc1\u63a5\u53e3&#39;, api_name = &#39;\u5237\u65b0token&#39;, title = &#39;\u6b63\u5411\u7528\u4f8b&#39;, level = &#39;\u4e2d&#39;\ncase_url = &#39;http://120.46.172.186:8080/refresh&#39;, case_method = &#39;GET&#39;\ncase_mime = None, case_data = None, expect_data = {&#39;message&#39;: &#39;\u5237\u65b0\u6210\u529f&#39;}\nsql_type = None, sql_data = None, update_key = None\n\n @allure.epic(\&#34;BPM_\u5f20\u4e09\&#34;)\n @pytest.mark.parametrize(\&#34;module_name, api_name, title, level, case_url, case_method, case_mime, case_data, expect_data, sql_type, sql_data, update_key\&#34;, ReadExcel(\&#34;BPM\&#34;, excel_path=excel_path).get_data())\n def test_bpm(self, db_fix, req_fix, module_name, api_name, title, level, case_url, case_method, case_mime, case_data, expect_data, sql_type, sql_data, update_key):\n allure.dynamic.feature(module_name)\n allure.dynamic.story(api_name)\n allure.dynamic.title(title)\n allure.dynamic.severity(level)\n # \u5224\u65adsql\u8bed\u53e5\u7684\u7c7b\u578b\u662f\u5426\u4e3adelete\n if sql_type == \&#34;delete\&#34;:\n # \u4f7f\u7528DB\u7c7b\u5bf9\u8c61\u6267\u884c\u5220\u9664\u7684sql\u8bed\u53e5\n db_fix.delete(sql_data)\n # \u4f7f\u7528RequestsMethod\u7c7b\u5bf9\u8c61\u53d1\u9001\u8bf7\u6c42--pass\n # \u5224\u65adsql\u8bed\u53e5\u7c7b\u578b\u662f\u5426\u4e3aselect\n elif sql_type == \&#34;select\&#34;:\n # \u4f7f\u7528DB\u7c7b\u5bf9\u8c61\u6267\u884c\u67e5\u8be2\u7684sql\u8bed\u53e5\uff0c\u5e76\u63a5\u6536\u67e5\u8be2\u7684\u7ed3\u679c\n select_result = db_fix.select(sql_data)\n # \u5c06\u67e5\u8be2\u7ed3\u679c\u66f4\u65b0\u5230\u7528\u4f8b\u6570\u636e\u4e2d\n case_data[update_key] = select_result\n # \u4f7f\u7528RequestsMethod\u7c7b\u5bf9\u8c61\u53d1\u9001\u8bf7\u6c42--pass\n \n # \u5224\u65adsql\u8bed\u53e5\u7684\u7c7b\u578b\u662f\u5426\u4e3aselect|delete\u6216\u8005\u4e3adelete|select\n elif sql_type == \&#34;select|delete\&#34; or sql_type == \&#34;delete|select\&#34;:\n # \u4f7f\u7528DB\u7c7b\u5bf9\u8c61\u6267\u884c\u5220\u9664\u7684sql\u8bed\u53e5\n db_fix.delete(sql_data.get(\&#34;delete\&#34;))\n # \u4f7f\u7528DB\u7c7b\u5bf9\u8c61\u6267\u884c\u67e5\u8be2\u7684sql\u8bed\u53e5\uff0c\u5e76\u63a5\u6536\u67e5\u8be2\u7684\u7ed3\u679c\n select_result = db_fix.select(sql_data.get(\&#34;select\&#34;))\n # \u5c06\u67e5\u8be2\u7ed3\u679c\u66f4\u65b0\u5230\u7528\u4f8b\u6570\u636e\u4e2d\n case_data[update_key] = select_result\n \n # \u4f7f\u7528RequestsMethod\u7c7b\u5bf9\u8c61\u53d1\u9001\u8bf7\u6c42\n res = req_fix.request_all(req_method=case_method, req_url=case_url, req_mime=case_mime, case_data=case_data)\n \n \n # \u65ad\u8a00\n try:\n for key in expect_data:\n&amp;gt; assert expect_data[key] == res.json().get(key)\nE AssertionError: assert &#39;\u5237\u65b0\u6210\u529f&#39; == None\nE + where None = &amp;lt;built-in method get of dict object at 0x0000018FED2AE280&amp;gt;(&#39;message&#39;)\nE + where &amp;lt;built-in method get of dict object at 0x0000018FED2AE280&amp;gt; = {&#39;account&#39;: &#39;&#39;, &#39;loginStatus&#39;: True, &#39;token&#39;: &#39;eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiJhZG1pbiIsInRlbmFudElkIjoiLTEiLCJleHAiOjE2OTkzMjg5NDUsImlhdCI6MTY5OTI0MjU0NX0.D9YH4bKjttn74Fb7KgS3XsBEXhtn2PLXqwN0gGqSzWEDfjoN28Ql-b8awn-dHZrupnM26deD5k14as8ScKo2xg&#39;, &#39;userAttrs&#39;: {}, ...}.get\nE + where {&#39;account&#39;: &#39;&#39;, &#39;loginStatus&#39;: True, &#39;token&#39;: &#39;eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiJhZG1pbiIsInRlbmFudElkIjoiLTEiLCJleHAiOjE2OTkzMjg5NDUsImlhdCI6MTY5OTI0MjU0NX0.D9YH4bKjttn74Fb7KgS3XsBEXhtn2PLXqwN0gGqSzWEDfjoN28Ql-b8awn-dHZrupnM26deD5k14as8ScKo2xg&#39;, &#39;userAttrs&#39;: {}, ...} = &amp;lt;bound method Response.json of &amp;lt;Response [200]&amp;gt;&amp;gt;()\nE + where &amp;lt;bound method Response.json of &amp;lt;Response [200]&amp;gt;&amp;gt; = &amp;lt;Response [200]&amp;gt;.json\n\ntest_zhangsan\\test_bpm.py:57: AssertionError\n\nDuring handling of the above exception, another exception occurred:\n\nself = &amp;lt;InterfaceAutoTest.test_case.test_zhangsan.test_bpm.TestBPM object at 0x0000018FED2DC970&amp;gt;\ndb_fix = &amp;lt;InterfaceAutoTest.common.db.DB object at 0x0000018FED3215B0&amp;gt;\nreq_fix = &amp;lt;InterfaceAutoTest.requests_method.requests_method.RequestsMethod object at 0x0000018FED36BD00&amp;gt;\nmodule_name = &#39;\u8ba4\u8bc1\u63a5\u53e3&#39;, api_name = &#39;\u5237\u65b0token&#39;, title = &#39;\u6b63\u5411\u7528\u4f8b&#39;, level = &#39;\u4e2d&#39;\ncase_url = &#39;http://120.46.172.186:8080/refresh&#39;, case_method = &#39;GET&#39;\ncase_mime = None, case_data = None, expect_data = {&#39;message&#39;: &#39;\u5237\u65b0\u6210\u529f&#39;}\nsql_type = None, sql_data = None, update_key = None\n\n @allure.epic(\&#34;BPM_\u5f20\u4e09\&#34;)\n @pytest.mark.parametrize(\&#34;module_name, api_name, title, level, case_url, case_method, case_mime, case_data, expect_data, sql_type, sql_data, update_key\&#34;, ReadExcel(\&#34;BPM\&#34;, excel_path=excel_path).get_data())\n def test_bpm(self, db_fix, req_fix, module_name, api_name, title, level, case_url, case_method, case_mime, case_data, expect_data, sql_type, sql_data, update_key):\n allure.dynamic.feature(module_name)\n allure.dynamic.story(api_name)\n allure.dynamic.title(title)\n allure.dynamic.severity(level)\n # \u5224\u65adsql\u8bed\u53e5\u7684\u7c7b\u578b\u662f\u5426\u4e3adelete\n if sql_type == \&#34;delete\&#34;:\n # \u4f7f\u7528DB\u7c7b\u5bf9\u8c61\u6267\u884c\u5220\u9664\u7684sql\u8bed\u53e5\n db_fix.delete(sql_data)\n # \u4f7f\u7528RequestsMethod\u7c7b\u5bf9\u8c61\u53d1\u9001\u8bf7\u6c42--pass\n # \u5224\u65adsql\u8bed\u53e5\u7c7b\u578b\u662f\u5426\u4e3aselect\n elif sql_type == \&#34;select\&#34;:\n # \u4f7f\u7528DB\u7c7b\u5bf9\u8c61\u6267\u884c\u67e5\u8be2\u7684sql\u8bed\u53e5\uff0c\u5e76\u63a5\u6536\u67e5\u8be2\u7684\u7ed3\u679c\n select_result = db_fix.select(sql_data)\n # \u5c06\u67e5\u8be2\u7ed3\u679c\u66f4\u65b0\u5230\u7528\u4f8b\u6570\u636e\u4e2d\n case_data[update_key] = select_result\n # \u4f7f\u7528RequestsMethod\u7c7b\u5bf9\u8c61\u53d1\u9001\u8bf7\u6c42--pass\n \n # \u5224\u65adsql\u8bed\u53e5\u7684\u7c7b\u578b\u662f\u5426\u4e3aselect|delete\u6216\u8005\u4e3adelete|select\n elif sql_type == \&#34;select|delete\&#34; or sql_type == \&#34;delete|select\&#34;:\n # \u4f7f\u7528DB\u7c7b\u5bf9\u8c61\u6267\u884c\u5220\u9664\u7684sql\u8bed\u53e5\n db_fix.delete(sql_data.get(\&#34;delete\&#34;))\n # \u4f7f\u7528DB\u7c7b\u5bf9\u8c61\u6267\u884c\u67e5\u8be2\u7684sql\u8bed\u53e5\uff0c\u5e76\u63a5\u6536\u67e5\u8be2\u7684\u7ed3\u679c\n select_result = db_fix.select(sql_data.get(\&#34;select\&#34;))\n # \u5c06\u67e5\u8be2\u7ed3\u679c\u66f4\u65b0\u5230\u7528\u4f8b\u6570\u636e\u4e2d\n case_data[update_key] = select_result\n \n # \u4f7f\u7528RequestsMethod\u7c7b\u5bf9\u8c61\u53d1\u9001\u8bf7\u6c42\n res = req_fix.request_all(req_method=case_method, req_url=case_url, req_mime=case_mime, case_data=case_data)\n \n \n # \u65ad\u8a00\n try:\n for key in expect_data:\n assert expect_data[key] == res.json().get(key)\n except:\n log.error(\&#34;\u65ad\u8a00\u5931\u8d25\&#34;+\&#34;\uff0c\u7528\u4f8b\u6570\u636e\u4e3a\uff1a\&#34;+str(case_data)+\&#34;,\u671f\u671b\u6570\u636e\u4e3a\uff1a\&#34;+str(expect_data)+\&#34;,\u670d\u52a1\u5668\u8fd4\u56de\u7684\u6570\u636e\u4e3a\uff1a\&#34;+res.text)\n&amp;gt; raise AssertionError(\&#34;\u65ad\u8a00\u5931\u8d25\&#34;)\nE AssertionError: \u65ad\u8a00\u5931\u8d25\n\ntest_zhangsan\\test_bpm.py:60: AssertionError\n\n------------------------------ Captured log call -------------------------------\nERROR \u9ec4\u603b:test_bpm.py:59 \u65ad\u8a00\u5931\u8d25\uff0c\u7528\u4f8b\u6570\u636e\u4e3a\uff1aNone,\u671f\u671b\u6570\u636e\u4e3a\uff1a{&#39;message&#39;: &#39;\u5237\u65b0\u6210\u529f&#39;},\u670d\u52a1\u5668\u8fd4\u56de\u7684\u6570\u636e\u4e3a\uff1a{\&#34;token\&#34;:\&#34;eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiJhZG1pbiIsInRlbmFudElkIjoiLTEiLCJleHAiOjE2OTkzMjg5NDUsImlhdCI6MTY5OTI0MjU0NX0.D9YH4bKjttn74Fb7KgS3XsBEXhtn2PLXqwN0gGqSzWEDfjoN28Ql-b8awn-dHZrupnM26deD5k14as8ScKo2xg\&#34;,\&#34;username\&#34;:\&#34;\&#34;,\&#34;account\&#34;:\&#34;\&#34;,\&#34;userId\&#34;:\&#34;\&#34;,\&#34;loginStatus\&#34;:true,\&#34;userAttrs\&#34;:{}}\n\n&#34;}], &#34;test_zhangsan/test_bpm.py::TestBPM::test_bpm[\u7ef4\u5ea6\u7ba1\u7406-\u6dfb\u52a0\u7ef4\u5ea6-\u6b63\u5411\u7528\u4f8b-\u9ad8-http://120.46.172.186:8080/api/demension/v1/dem/addDem-post-json-case_data11-expect_data11-delete-DELETE FROM uc_demension WHERE `CODE_`=\&#34;dem_test57_abc\&#34;;-None]&#34;: [{&#34;extras&#34;: [], &#34;result&#34;: &#34;Passed&#34;, &#34;testId&#34;: &#34;test_zhangsan/test_bpm.py::TestBPM::test_bpm[\u7ef4\u5ea6\u7ba1\u7406-\u6dfb\u52a0\u7ef4\u5ea6-\u6b63\u5411\u7528\u4f8b-\u9ad8-http://120.46.172.186:8080/api/demension/v1/dem/addDem-post-json-case_data11-expect_data11-delete-DELETE FROM uc_demension WHERE `CODE_`=\&#34;dem_test57_abc\&#34;;-None]&#34;, &#34;duration&#34;: &#34;136 ms&#34;, &#34;resultsTableRow&#34;: [&#34;&lt;td class=\&#34;col-result\&#34;&gt;Passed&lt;/td&gt;&#34;, &#34;&lt;td class=\&#34;col-testId\&#34;&gt;test_zhangsan/test_bpm.py::TestBPM::test_bpm[\u7ef4\u5ea6\u7ba1\u7406-\u6dfb\u52a0\u7ef4\u5ea6-\u6b63\u5411\u7528\u4f8b-\u9ad8-http://120.46.172.186:8080/api/demension/v1/dem/addDem-post-json-case_data11-expect_data11-delete-DELETE FROM uc_demension WHERE `CODE_`=\&#34;dem_test57_abc\&#34;;-None]&lt;/td&gt;&#34;, &#34;&lt;td class=\&#34;col-duration\&#34;&gt;136 ms&lt;/td&gt;&#34;, &#34;&lt;td class=\&#34;col-links\&#34;&gt;&lt;/td&gt;&#34;], &#34;log&#34;: &#34;No log output captured.&#34;}], &#34;test_zhangsan/test_bpm.py::TestBPM::test_bpm[\u7ef4\u5ea6\u7ba1\u7406-\u6839\u636e\u7ef4\u5ea6\u7f16\u7801\u83b7\u53d6\u7ef4\u5ea6\u4fe1\u606f-\u6b63\u5411\u7528\u4f8b-\u4e2d-http://120.46.172.186:8080/api/demension/v1/dem/getDem-GET-query-case_data12-expect_data12-None-None-None]&#34;: [{&#34;extras&#34;: [], &#34;result&#34;: &#34;Passed&#34;, &#34;testId&#34;: &#34;test_zhangsan/test_bpm.py::TestBPM::test_bpm[\u7ef4\u5ea6\u7ba1\u7406-\u6839\u636e\u7ef4\u5ea6\u7f16\u7801\u83b7\u53d6\u7ef4\u5ea6\u4fe1\u606f-\u6b63\u5411\u7528\u4f8b-\u4e2d-http://120.46.172.186:8080/api/demension/v1/dem/getDem-GET-query-case_data12-expect_data12-None-None-None]&#34;, &#34;duration&#34;: &#34;46 ms&#34;, &#34;resultsTableRow&#34;: [&#34;&lt;td class=\&#34;col-result\&#34;&gt;Passed&lt;/td&gt;&#34;, &#34;&lt;td class=\&#34;col-testId\&#34;&gt;test_zhangsan/test_bpm.py::TestBPM::test_bpm[\u7ef4\u5ea6\u7ba1\u7406-\u6839\u636e\u7ef4\u5ea6\u7f16\u7801\u83b7\u53d6\u7ef4\u5ea6\u4fe1\u606f-\u6b63\u5411\u7528\u4f8b-\u4e2d-http://120.46.172.186:8080/api/demension/v1/dem/getDem-GET-query-case_data12-expect_data12-None-None-None]&lt;/td&gt;&#34;, &#34;&lt;td class=\&#34;col-duration\&#34;&gt;46 ms&lt;/td&gt;&#34;, &#34;&lt;td class=\&#34;col-links\&#34;&gt;&lt;/td&gt;&#34;], &#34;log&#34;: &#34;No log output captured.&#34;}], &#34;test_zhangsan/test_bpm.py::TestBPM::test_bpm[\u7ec4\u7ec7\u7ba1\u7406-\u6dfb\u52a0\u7ec4\u7ec7-\u6b63\u5411\u7528\u4f8b-\u9ad8-http://120.46.172.186:8080/api/org/v1/org/addOrg-POST-application/json-case_data13-expect_data13-select|delete-sql_data13-demId]&#34;: [{&#34;extras&#34;: [], &#34;result&#34;: &#34;Passed&#34;, &#34;testId&#34;: &#34;test_zhangsan/test_bpm.py::TestBPM::test_bpm[\u7ec4\u7ec7\u7ba1\u7406-\u6dfb\u52a0\u7ec4\u7ec7-\u6b63\u5411\u7528\u4f8b-\u9ad8-http://120.46.172.186:8080/api/org/v1/org/addOrg-POST-application/json-case_data13-expect_data13-select|delete-sql_data13-demId]&#34;, &#34;duration&#34;: &#34;175 ms&#34;, &#34;resultsTableRow&#34;: [&#34;&lt;td class=\&#34;col-result\&#34;&gt;Passed&lt;/td&gt;&#34;, &#34;&lt;td class=\&#34;col-testId\&#34;&gt;test_zhangsan/test_bpm.py::TestBPM::test_bpm[\u7ec4\u7ec7\u7ba1\u7406-\u6dfb\u52a0\u7ec4\u7ec7-\u6b63\u5411\u7528\u4f8b-\u9ad8-http://120.46.172.186:8080/api/org/v1/org/addOrg-POST-application/json-case_data13-expect_data13-select|delete-sql_data13-demId]&lt;/td&gt;&#34;, &#34;&lt;td class=\&#34;col-duration\&#34;&gt;175 ms&lt;/td&gt;&#34;, &#34;&lt;td class=\&#34;col-links\&#34;&gt;&lt;/td&gt;&#34;], &#34;log&#34;: &#34;No log output captured.&#34;}], &#34;test_zhangsan/test_bpm.py::TestBPM::test_bpm[\u7ec4\u7ec7\u7ba1\u7406-\u6dfb\u52a0\u7ec4\u7ec7\u53c2\u6570-\u6b63\u5411\u7528\u4f8b-\u9ad8-http://120.46.172.186:8080/api/org/v1/orgParam/saveOrgParams-POST-body|query-case_data14-expect_data14-None-None-None]&#34;: [{&#34;extras&#34;: [], &#34;result&#34;: &#34;Passed&#34;, &#34;testId&#34;: &#34;test_zhangsan/test_bpm.py::TestBPM::test_bpm[\u7ec4\u7ec7\u7ba1\u7406-\u6dfb\u52a0\u7ec4\u7ec7\u53c2\u6570-\u6b63\u5411\u7528\u4f8b-\u9ad8-http://120.46.172.186:8080/api/org/v1/orgParam/saveOrgParams-POST-body|query-case_data14-expect_data14-None-None-None]&#34;, &#34;duration&#34;: &#34;53 ms&#34;, &#34;resultsTableRow&#34;: [&#34;&lt;td class=\&#34;col-result\&#34;&gt;Passed&lt;/td&gt;&#34;, &#34;&lt;td class=\&#34;col-testId\&#34;&gt;test_zhangsan/test_bpm.py::TestBPM::test_bpm[\u7ec4\u7ec7\u7ba1\u7406-\u6dfb\u52a0\u7ec4\u7ec7\u53c2\u6570-\u6b63\u5411\u7528\u4f8b-\u9ad8-http://120.46.172.186:8080/api/org/v1/orgParam/saveOrgParams-POST-body|query-case_data14-expect_data14-None-None-None]&lt;/td&gt;&#34;, &#34;&lt;td class=\&#34;col-duration\&#34;&gt;53 ms&lt;/td&gt;&#34;, &#34;&lt;td class=\&#34;col-links\&#34;&gt;&lt;/td&gt;&#34;], &#34;log&#34;: &#34;No log output captured.&#34;}], &#34;test_zhangsan/test_bpm.py::TestBPM::test_bpm[\u7ec4\u7ec7\u7ba1\u7406-\u5220\u9664\u7ec4\u7ec7-\u6b63\u5411\u7528\u4f8b-\u9ad8-http://120.46.172.186:8080/api/org/v1/org/deleteOrg-POST-x-www-form-urlencoded-test_org_57-expect_data15-None-None-None]&#34;: [{&#34;extras&#34;: [], &#34;result&#34;: &#34;Passed&#34;, &#34;testId&#34;: &#34;test_zhangsan/test_bpm.py::TestBPM::test_bpm[\u7ec4\u7ec7\u7ba1\u7406-\u5220\u9664\u7ec4\u7ec7-\u6b63\u5411\u7528\u4f8b-\u9ad8-http://120.46.172.186:8080/api/org/v1/org/deleteOrg-POST-x-www-form-urlencoded-test_org_57-expect_data15-None-None-None]&#34;, &#34;duration&#34;: &#34;55 ms&#34;, &#34;resultsTableRow&#34;: [&#34;&lt;td class=\&#34;col-result\&#34;&gt;Passed&lt;/td&gt;&#34;, &#34;&lt;td class=\&#34;col-testId\&#34;&gt;test_zhangsan/test_bpm.py::TestBPM::test_bpm[\u7ec4\u7ec7\u7ba1\u7406-\u5220\u9664\u7ec4\u7ec7-\u6b63\u5411\u7528\u4f8b-\u9ad8-http://120.46.172.186:8080/api/org/v1/org/deleteOrg-POST-x-www-form-urlencoded-test_org_57-expect_data15-None-None-None]&lt;/td&gt;&#34;, &#34;&lt;td class=\&#34;col-duration\&#34;&gt;55 ms&lt;/td&gt;&#34;, &#34;&lt;td class=\&#34;col-links\&#34;&gt;&lt;/td&gt;&#34;], &#34;log&#34;: &#34;No log output captured.&#34;}], &#34;test_zhangsan/test_bpm.py::TestBPM::test_bpm[\u7ef4\u5ea6\u7ba1\u7406-\u6839\u636e\u7ef4\u5ea6\u7f16\u7801\u5220\u9664\u7ef4\u5ea6-\u6b63\u5411\u7528\u4f8b-\u4e2d-http://120.46.172.186:8080/api/demension/v1/dem/deleteDemByIds-DELETE-query-case_data16-expect_data16-select-SELECT ID_ from uc_demension WHERE `CODE_`=\&#34;dem_test57_abc\&#34;;-ids]&#34;: [{&#34;extras&#34;: [], &#34;result&#34;: &#34;Failed&#34;, &#34;testId&#34;: &#34;test_zhangsan/test_bpm.py::TestBPM::test_bpm[\u7ef4\u5ea6\u7ba1\u7406-\u6839\u636e\u7ef4\u5ea6\u7f16\u7801\u5220\u9664\u7ef4\u5ea6-\u6b63\u5411\u7528\u4f8b-\u4e2d-http://120.46.172.186:8080/api/demension/v1/dem/deleteDemByIds-DELETE-query-case_data16-expect_data16-select-SELECT ID_ from uc_demension WHERE `CODE_`=\&#34;dem_test57_abc\&#34;;-ids]&#34;, &#34;duration&#34;: &#34;93 ms&#34;, &#34;resultsTableRow&#34;: [&#34;&lt;td class=\&#34;col-result\&#34;&gt;Failed&lt;/td&gt;&#34;, &#34;&lt;td class=\&#34;col-testId\&#34;&gt;test_zhangsan/test_bpm.py::TestBPM::test_bpm[\u7ef4\u5ea6\u7ba1\u7406-\u6839\u636e\u7ef4\u5ea6\u7f16\u7801\u5220\u9664\u7ef4\u5ea6-\u6b63\u5411\u7528\u4f8b-\u4e2d-http://120.46.172.186:8080/api/demension/v1/dem/deleteDemByIds-DELETE-query-case_data16-expect_data16-select-SELECT ID_ from uc_demension WHERE `CODE_`=\&#34;dem_test57_abc\&#34;;-ids]&lt;/td&gt;&#34;, &#34;&lt;td class=\&#34;col-duration\&#34;&gt;93 ms&lt;/td&gt;&#34;, &#34;&lt;td class=\&#34;col-links\&#34;&gt;&lt;/td&gt;&#34;], &#34;log&#34;: &#34;self = &amp;lt;InterfaceAutoTest.test_case.test_zhangsan.test_bpm.TestBPM object at 0x0000018FED321040&amp;gt;\ndb_fix = &amp;lt;InterfaceAutoTest.common.db.DB object at 0x0000018FED3215B0&amp;gt;\nreq_fix = &amp;lt;InterfaceAutoTest.requests_method.requests_method.RequestsMethod object at 0x0000018FED36BD00&amp;gt;\nmodule_name = &#39;\u7ef4\u5ea6\u7ba1\u7406&#39;, api_name = &#39;\u6839\u636e\u7ef4\u5ea6\u7f16\u7801\u5220\u9664\u7ef4\u5ea6&#39;, title = &#39;\u6b63\u5411\u7528\u4f8b&#39;, level = &#39;\u4e2d&#39;\ncase_url = &#39;http://120.46.172.186:8080/api/demension/v1/dem/deleteDemByIds&#39;\ncase_method = &#39;DELETE&#39;, case_mime = &#39;query&#39;\ncase_data = {&#39;ids&#39;: &#39;1721374116574937088&#39;}\nexpect_data = {&#39;message&#39;: &#39;\u5220\u9664\u7ef4\u5ea6\u6210\u529f&#39;, &#39;state&#39;: True}, sql_type = &#39;select&#39;\nsql_data = &#39;SELECT ID_ from uc_demension WHERE `CODE_`=\&#34;dem_test57_abc\&#34;;&#39;\nupdate_key = &#39;ids&#39;\n\n @allure.epic(\&#34;BPM_\u5f20\u4e09\&#34;)\n @pytest.mark.parametrize(\&#34;module_name, api_name, title, level, case_url, case_method, case_mime, case_data, expect_data, sql_type, sql_data, update_key\&#34;, ReadExcel(\&#34;BPM\&#34;, excel_path=excel_path).get_data())\n def test_bpm(self, db_fix, req_fix, module_name, api_name, title, level, case_url, case_method, case_mime, case_data, expect_data, sql_type, sql_data, update_key):\n allure.dynamic.feature(module_name)\n allure.dynamic.story(api_name)\n allure.dynamic.title(title)\n allure.dynamic.severity(level)\n # \u5224\u65adsql\u8bed\u53e5\u7684\u7c7b\u578b\u662f\u5426\u4e3adelete\n if sql_type == \&#34;delete\&#34;:\n # \u4f7f\u7528DB\u7c7b\u5bf9\u8c61\u6267\u884c\u5220\u9664\u7684sql\u8bed\u53e5\n db_fix.delete(sql_data)\n # \u4f7f\u7528RequestsMethod\u7c7b\u5bf9\u8c61\u53d1\u9001\u8bf7\u6c42--pass\n # \u5224\u65adsql\u8bed\u53e5\u7c7b\u578b\u662f\u5426\u4e3aselect\n elif sql_type == \&#34;select\&#34;:\n # \u4f7f\u7528DB\u7c7b\u5bf9\u8c61\u6267\u884c\u67e5\u8be2\u7684sql\u8bed\u53e5\uff0c\u5e76\u63a5\u6536\u67e5\u8be2\u7684\u7ed3\u679c\n select_result = db_fix.select(sql_data)\n # \u5c06\u67e5\u8be2\u7ed3\u679c\u66f4\u65b0\u5230\u7528\u4f8b\u6570\u636e\u4e2d\n case_data[update_key] = select_result\n # \u4f7f\u7528RequestsMethod\u7c7b\u5bf9\u8c61\u53d1\u9001\u8bf7\u6c42--pass\n \n # \u5224\u65adsql\u8bed\u53e5\u7684\u7c7b\u578b\u662f\u5426\u4e3aselect|delete\u6216\u8005\u4e3adelete|select\n elif sql_type == \&#34;select|delete\&#34; or sql_type == \&#34;delete|select\&#34;:\n # \u4f7f\u7528DB\u7c7b\u5bf9\u8c61\u6267\u884c\u5220\u9664\u7684sql\u8bed\u53e5\n db_fix.delete(sql_data.get(\&#34;delete\&#34;))\n # \u4f7f\u7528DB\u7c7b\u5bf9\u8c61\u6267\u884c\u67e5\u8be2\u7684sql\u8bed\u53e5\uff0c\u5e76\u63a5\u6536\u67e5\u8be2\u7684\u7ed3\u679c\n select_result = db_fix.select(sql_data.get(\&#34;select\&#34;))\n # \u5c06\u67e5\u8be2\u7ed3\u679c\u66f4\u65b0\u5230\u7528\u4f8b\u6570\u636e\u4e2d\n case_data[update_key] = select_result\n \n # \u4f7f\u7528RequestsMethod\u7c7b\u5bf9\u8c61\u53d1\u9001\u8bf7\u6c42\n res = req_fix.request_all(req_method=case_method, req_url=case_url, req_mime=case_mime, case_data=case_data)\n \n \n # \u65ad\u8a00\n try:\n for key in expect_data:\n&amp;gt; assert expect_data[key] == res.json().get(key)\nE AssertionError: assert &#39;\u5220\u9664\u7ef4\u5ea6\u6210\u529f&#39; == &#39;\u5220\u9664\u7ef4\u5ea6\u6210\u529f\uff01&#39;\nE - \u5220\u9664\u7ef4\u5ea6\u6210\u529f\uff01\nE ? -\nE + \u5220\u9664\u7ef4\u5ea6\u6210\u529f\n\ntest_zhangsan\\test_bpm.py:57: AssertionError\n\nDuring handling of the above exception, another exception occurred:\n\nself = &amp;lt;InterfaceAutoTest.test_case.test_zhangsan.test_bpm.TestBPM object at 0x0000018FED321040&amp;gt;\ndb_fix = &amp;lt;InterfaceAutoTest.common.db.DB object at 0x0000018FED3215B0&amp;gt;\nreq_fix = &amp;lt;InterfaceAutoTest.requests_method.requests_method.RequestsMethod object at 0x0000018FED36BD00&amp;gt;\nmodule_name = &#39;\u7ef4\u5ea6\u7ba1\u7406&#39;, api_name = &#39;\u6839\u636e\u7ef4\u5ea6\u7f16\u7801\u5220\u9664\u7ef4\u5ea6&#39;, title = &#39;\u6b63\u5411\u7528\u4f8b&#39;, level = &#39;\u4e2d&#39;\ncase_url = &#39;http://120.46.172.186:8080/api/demension/v1/dem/deleteDemByIds&#39;\ncase_method = &#39;DELETE&#39;, case_mime = &#39;query&#39;\ncase_data = {&#39;ids&#39;: &#39;1721374116574937088&#39;}\nexpect_data = {&#39;message&#39;: &#39;\u5220\u9664\u7ef4\u5ea6\u6210\u529f&#39;, &#39;state&#39;: True}, sql_type = &#39;select&#39;\nsql_data = &#39;SELECT ID_ from uc_demension WHERE `CODE_`=\&#34;dem_test57_abc\&#34;;&#39;\nupdate_key = &#39;ids&#39;\n\n @allure.epic(\&#34;BPM_\u5f20\u4e09\&#34;)\n @pytest.mark.parametrize(\&#34;module_name, api_name, title, level, case_url, case_method, case_mime, case_data, expect_data, sql_type, sql_data, update_key\&#34;, ReadExcel(\&#34;BPM\&#34;, excel_path=excel_path).get_data())\n def test_bpm(self, db_fix, req_fix, module_name, api_name, title, level, case_url, case_method, case_mime, case_data, expect_data, sql_type, sql_data, update_key):\n allure.dynamic.feature(module_name)\n allure.dynamic.story(api_name)\n allure.dynamic.title(title)\n allure.dynamic.severity(level)\n # \u5224\u65adsql\u8bed\u53e5\u7684\u7c7b\u578b\u662f\u5426\u4e3adelete\n if sql_type == \&#34;delete\&#34;:\n # \u4f7f\u7528DB\u7c7b\u5bf9\u8c61\u6267\u884c\u5220\u9664\u7684sql\u8bed\u53e5\n db_fix.delete(sql_data)\n # \u4f7f\u7528RequestsMethod\u7c7b\u5bf9\u8c61\u53d1\u9001\u8bf7\u6c42--pass\n # \u5224\u65adsql\u8bed\u53e5\u7c7b\u578b\u662f\u5426\u4e3aselect\n elif sql_type == \&#34;select\&#34;:\n # \u4f7f\u7528DB\u7c7b\u5bf9\u8c61\u6267\u884c\u67e5\u8be2\u7684sql\u8bed\u53e5\uff0c\u5e76\u63a5\u6536\u67e5\u8be2\u7684\u7ed3\u679c\n select_result = db_fix.select(sql_data)\n # \u5c06\u67e5\u8be2\u7ed3\u679c\u66f4\u65b0\u5230\u7528\u4f8b\u6570\u636e\u4e2d\n case_data[update_key] = select_result\n # \u4f7f\u7528RequestsMethod\u7c7b\u5bf9\u8c61\u53d1\u9001\u8bf7\u6c42--pass\n \n # \u5224\u65adsql\u8bed\u53e5\u7684\u7c7b\u578b\u662f\u5426\u4e3aselect|delete\u6216\u8005\u4e3adelete|select\n elif sql_type == \&#34;select|delete\&#34; or sql_type == \&#34;delete|select\&#34;:\n # \u4f7f\u7528DB\u7c7b\u5bf9\u8c61\u6267\u884c\u5220\u9664\u7684sql\u8bed\u53e5\n db_fix.delete(sql_data.get(\&#34;delete\&#34;))\n # \u4f7f\u7528DB\u7c7b\u5bf9\u8c61\u6267\u884c\u67e5\u8be2\u7684sql\u8bed\u53e5\uff0c\u5e76\u63a5\u6536\u67e5\u8be2\u7684\u7ed3\u679c\n select_result = db_fix.select(sql_data.get(\&#34;select\&#34;))\n # \u5c06\u67e5\u8be2\u7ed3\u679c\u66f4\u65b0\u5230\u7528\u4f8b\u6570\u636e\u4e2d\n case_data[update_key] = select_result\n \n # \u4f7f\u7528RequestsMethod\u7c7b\u5bf9\u8c61\u53d1\u9001\u8bf7\u6c42\n res = req_fix.request_all(req_method=case_method, req_url=case_url, req_mime=case_mime, case_data=case_data)\n \n \n # \u65ad\u8a00\n try:\n for key in expect_data:\n assert expect_data[key] == res.json().get(key)\n except:\n log.error(\&#34;\u65ad\u8a00\u5931\u8d25\&#34;+\&#34;\uff0c\u7528\u4f8b\u6570\u636e\u4e3a\uff1a\&#34;+str(case_data)+\&#34;,\u671f\u671b\u6570\u636e\u4e3a\uff1a\&#34;+str(expect_data)+\&#34;,\u670d\u52a1\u5668\u8fd4\u56de\u7684\u6570\u636e\u4e3a\uff1a\&#34;+res.text)\n&amp;gt; raise AssertionError(\&#34;\u65ad\u8a00\u5931\u8d25\&#34;)\nE AssertionError: \u65ad\u8a00\u5931\u8d25\n\ntest_zhangsan\\test_bpm.py:60: AssertionError\n\n------------------------------ Captured log call -------------------------------\nERROR \u9ec4\u603b:test_bpm.py:59 \u65ad\u8a00\u5931\u8d25\uff0c\u7528\u4f8b\u6570\u636e\u4e3a\uff1a{&#39;ids&#39;: &#39;1721374116574937088&#39;},\u671f\u671b\u6570\u636e\u4e3a\uff1a{&#39;state&#39;: True, &#39;message&#39;: &#39;\u5220\u9664\u7ef4\u5ea6\u6210\u529f&#39;},\u670d\u52a1\u5668\u8fd4\u56de\u7684\u6570\u636e\u4e3a\uff1a{\&#34;state\&#34;:true,\&#34;message\&#34;:\&#34;\u5220\u9664\u7ef4\u5ea6\u6210\u529f\uff01\&#34;,\&#34;value\&#34;:\&#34;\&#34;}\n\n&#34;}]}, &#34;renderCollapsed&#34;: [&#34;passed&#34;], &#34;initialSort&#34;: &#34;result&#34;, &#34;title&#34;: &#34;test_zhangsan.html&#34;}"></div>
<script>
(function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c="function"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error("Cannot find module '"+i+"'");throw a.code="MODULE_NOT_FOUND",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u="function"==typeof require&&require,i=0;i<t.length;i++)o(t[i]);return o}return r})()({1:[function(require,module,exports){
const { getCollapsedCategory, setCollapsedIds } = require('./storage.js')
class DataManager {
setManager(data) {
const collapsedCategories = [...getCollapsedCategory(data.renderCollapsed)]
const collapsedIds = []
const tests = Object.values(data.tests).flat().map((test, index) => {
const collapsed = collapsedCategories.includes(test.result.toLowerCase())
const id = `test_${index}`
if (collapsed) {
collapsedIds.push(id)
}
return {
...test,
id,
collapsed,
}
})
const dataBlob = { ...data, tests }
this.data = { ...dataBlob }
this.renderData = { ...dataBlob }
setCollapsedIds(collapsedIds)
}
get allData() {
return { ...this.data }
}
resetRender() {
this.renderData = { ...this.data }
}
setRender(data) {
this.renderData.tests = [...data]
}
toggleCollapsedItem(id) {
this.renderData.tests = this.renderData.tests.map((test) =>
test.id === id ? { ...test, collapsed: !test.collapsed } : test,
)
}
set allCollapsed(collapsed) {
this.renderData = { ...this.renderData, tests: [...this.renderData.tests.map((test) => (
{ ...test, collapsed }
))] }
}
get testSubset() {
return [...this.renderData.tests]
}
get environment() {
return this.renderData.environment
}
get initialSort() {
return this.data.initialSort
}
}
module.exports = {
manager: new DataManager(),
}
},{"./storage.js":8}],2:[function(require,module,exports){
const mediaViewer = require('./mediaviewer.js')
const templateEnvRow = document.getElementById('template_environment_row')
const templateResult = document.getElementById('template_results-table__tbody')
function htmlToElements(html) {
const temp = document.createElement('template')
temp.innerHTML = html
return temp.content.childNodes
}
const find = (selector, elem) => {
if (!elem) {
elem = document
}
return elem.querySelector(selector)
}
const findAll = (selector, elem) => {
if (!elem) {
elem = document
}
return [...elem.querySelectorAll(selector)]
}
const dom = {
getStaticRow: (key, value) => {
const envRow = templateEnvRow.content.cloneNode(true)
const isObj = typeof value === 'object' && value !== null
const values = isObj ? Object.keys(value).map((k) => `${k}: ${value[k]}`) : null
const valuesElement = htmlToElements(
values ? `<ul>${values.map((val) => `<li>${val}</li>`).join('')}<ul>` : `<div>${value}</div>`)[0]
const td = findAll('td', envRow)
td[0].textContent = key
td[1].appendChild(valuesElement)
return envRow
},
getResultTBody: ({ testId, id, log, extras, resultsTableRow, tableHtml, result, collapsed }) => {
const resultBody = templateResult.content.cloneNode(true)
resultBody.querySelector('tbody').classList.add(result.toLowerCase())
resultBody.querySelector('tbody').id = testId
resultBody.querySelector('.collapsible').dataset.id = id
resultsTableRow.forEach((html) => {
const t = document.createElement('template')
t.innerHTML = html
resultBody.querySelector('.collapsible').appendChild(t.content)
})
if (log) {
// Wrap lines starting with "E" with span.error to color those lines red
const wrappedLog = log.replace(/^E.*$/gm, (match) => `<span class="error">${match}</span>`)
resultBody.querySelector('.log').innerHTML = wrappedLog
} else {
resultBody.querySelector('.log').remove()
}
if (collapsed) {
resultBody.querySelector('.collapsible > td')?.classList.add('collapsed')
resultBody.querySelector('.extras-row').classList.add('hidden')
} else {
resultBody.querySelector('.collapsible > td')?.classList.remove('collapsed')
}
const media = []
extras?.forEach(({ name, format_type, content }) => {
if (['image', 'video'].includes(format_type)) {
media.push({ path: content, name, format_type })
}
if (format_type === 'html') {
resultBody.querySelector('.extraHTML').insertAdjacentHTML('beforeend', `<div>${content}</div>`)
}
})
mediaViewer.setup(resultBody, media)
// Add custom html from the pytest_html_results_table_html hook
tableHtml?.forEach((item) => {
resultBody.querySelector('td[class="extra"]').insertAdjacentHTML('beforeend', item)
})
return resultBody
},
}
module.exports = {
dom,
htmlToElements,
find,
findAll,
}
},{"./mediaviewer.js":6}],3:[function(require,module,exports){
const { manager } = require('./datamanager.js')
const { doSort } = require('./sort.js')
const storageModule = require('./storage.js')
const getFilteredSubSet = (filter) =>
manager.allData.tests.filter(({ result }) => filter.includes(result.toLowerCase()))
const doInitFilter = () => {
const currentFilter = storageModule.getVisible()
const filteredSubset = getFilteredSubSet(currentFilter)
manager.setRender(filteredSubset)
}
const doFilter = (type, show) => {
if (show) {
storageModule.showCategory(type)
} else {
storageModule.hideCategory(type)
}
const currentFilter = storageModule.getVisible()
const filteredSubset = getFilteredSubSet(currentFilter)
manager.setRender(filteredSubset)
const sortColumn = storageModule.getSort()
doSort(sortColumn, true)
}
module.exports = {
doFilter,
doInitFilter,
}
},{"./datamanager.js":1,"./sort.js":7,"./storage.js":8}],4:[function(require,module,exports){
const { redraw, bindEvents, renderStatic } = require('./main.js')
const { doInitFilter } = require('./filter.js')
const { doInitSort } = require('./sort.js')
const { manager } = require('./datamanager.js')
const data = JSON.parse(document.getElementById('data-container').dataset.jsonblob)
function init() {
manager.setManager(data)
doInitFilter()
doInitSort()
renderStatic()
redraw()
bindEvents()
}
init()
},{"./datamanager.js":1,"./filter.js":3,"./main.js":5,"./sort.js":7}],5:[function(require,module,exports){
const { dom, find, findAll } = require('./dom.js')
const { manager } = require('./datamanager.js')
const { doSort } = require('./sort.js')
const { doFilter } = require('./filter.js')
const {
getVisible,
getCollapsedIds,
setCollapsedIds,
getSort,
getSortDirection,
possibleFilters,
} = require('./storage.js')
const removeChildren = (node) => {
while (node.firstChild) {
node.removeChild(node.firstChild)
}
}
const renderStatic = () => {
const renderEnvironmentTable = () => {
const environment = manager.environment
const rows = Object.keys(environment).map((key) => dom.getStaticRow(key, environment[key]))
const table = document.getElementById('environment')
removeChildren(table)
rows.forEach((row) => table.appendChild(row))
}
renderEnvironmentTable()
}
const addItemToggleListener = (elem) => {
elem.addEventListener('click', ({ target }) => {
const id = target.parentElement.dataset.id
manager.toggleCollapsedItem(id)
const collapsedIds = getCollapsedIds()
if (collapsedIds.includes(id)) {
const updated = collapsedIds.filter((item) => item !== id)
setCollapsedIds(updated)
} else {
collapsedIds.push(id)
setCollapsedIds(collapsedIds)
}
redraw()
})
}
const renderContent = (tests) => {
const sortAttr = getSort(manager.initialSort)
const sortAsc = JSON.parse(getSortDirection())
const rows = tests.map(dom.getResultTBody)
const table = document.getElementById('results-table')
const tableHeader = document.getElementById('results-table-head')
const newTable = document.createElement('table')
newTable.id = 'results-table'
// remove all sorting classes and set the relevant
findAll('.sortable', tableHeader).forEach((elem) => elem.classList.remove('asc', 'desc'))
tableHeader.querySelector(`.sortable[data-column-type="${sortAttr}"]`).classList.add(sortAsc ? 'desc' : 'asc')
newTable.appendChild(tableHeader)
if (!rows.length) {
const emptyTable = document.getElementById('template_results-table__body--empty').content.cloneNode(true)
newTable.appendChild(emptyTable)
} else {
rows.forEach((row) => {
if (!!row) {
findAll('.collapsible td:not(.col-links', row).forEach(addItemToggleListener)
find('.logexpander', row).addEventListener('click',
(evt) => evt.target.parentNode.classList.toggle('expanded'),
)
newTable.appendChild(row)
}
})
}
table.replaceWith(newTable)
}
const renderDerived = () => {
const currentFilter = getVisible()
possibleFilters.forEach((result) => {
const input = document.querySelector(`input[data-test-result="${result}"]`)
input.checked = currentFilter.includes(result)
})
}
const bindEvents = () => {
const filterColumn = (evt) => {
const { target: element } = evt
const { testResult } = element.dataset
doFilter(testResult, element.checked)
const collapsedIds = getCollapsedIds()
const updated = manager.renderData.tests.map((test) => {
return {
...test,
collapsed: collapsedIds.includes(test.id),
}
})
manager.setRender(updated)
redraw()
}
const header = document.getElementById('environment-header')
header.addEventListener('click', () => {
const table = document.getElementById('environment')
table.classList.toggle('hidden')
header.classList.toggle('collapsed')
})
findAll('input[name="filter_checkbox"]').forEach((elem) => {
elem.addEventListener('click', filterColumn)
})
findAll('.sortable').forEach((elem) => {
elem.addEventListener('click', (evt) => {
const { target: element } = evt
const { columnType } = element.dataset
doSort(columnType)
redraw()
})
})
document.getElementById('show_all_details').addEventListener('click', () => {
manager.allCollapsed = false
setCollapsedIds([])
redraw()
})
document.getElementById('hide_all_details').addEventListener('click', () => {
manager.allCollapsed = true
const allIds = manager.renderData.tests.map((test) => test.id)
setCollapsedIds(allIds)
redraw()
})
}
const redraw = () => {
const { testSubset } = manager
renderContent(testSubset)
renderDerived()
}
module.exports = {
redraw,
bindEvents,
renderStatic,
}
},{"./datamanager.js":1,"./dom.js":2,"./filter.js":3,"./sort.js":7,"./storage.js":8}],6:[function(require,module,exports){
class MediaViewer {
constructor(assets) {
this.assets = assets
this.index = 0
}
nextActive() {
this.index = this.index === this.assets.length - 1 ? 0 : this.index + 1
return [this.activeFile, this.index]
}
prevActive() {
this.index = this.index === 0 ? this.assets.length - 1 : this.index -1
return [this.activeFile, this.index]
}
get currentIndex() {
return this.index
}
get activeFile() {
return this.assets[this.index]
}
}
const setup = (resultBody, assets) => {
if (!assets.length) {
resultBody.querySelector('.media').classList.add('hidden')
return
}
const mediaViewer = new MediaViewer(assets)
const container = resultBody.querySelector('.media-container')
const leftArrow = resultBody.querySelector('.media-container__nav--left')
const rightArrow = resultBody.querySelector('.media-container__nav--right')
const mediaName = resultBody.querySelector('.media__name')
const counter = resultBody.querySelector('.media__counter')
const imageEl = resultBody.querySelector('img')
const sourceEl = resultBody.querySelector('source')
const videoEl = resultBody.querySelector('video')
const setImg = (media, index) => {
if (media?.format_type === 'image') {
imageEl.src = media.path
imageEl.classList.remove('hidden')
videoEl.classList.add('hidden')
} else if (media?.format_type === 'video') {
sourceEl.src = media.path
videoEl.classList.remove('hidden')
imageEl.classList.add('hidden')
}
mediaName.innerText = media?.name
counter.innerText = `${index + 1} / ${assets.length}`
}
setImg(mediaViewer.activeFile, mediaViewer.currentIndex)
const moveLeft = () => {
const [media, index] = mediaViewer.prevActive()
setImg(media, index)
}
const doRight = () => {
const [media, index] = mediaViewer.nextActive()
setImg(media, index)
}
const openImg = () => {
window.open(mediaViewer.activeFile.path, '_blank')
}
if (assets.length === 1) {
container.classList.add('media-container--fullscreen')
} else {
leftArrow.addEventListener('click', moveLeft)
rightArrow.addEventListener('click', doRight)
}
imageEl.addEventListener('click', openImg)
}
module.exports = {
setup,
}
},{}],7:[function(require,module,exports){
const { manager } = require('./datamanager.js')
const storageModule = require('./storage.js')
const genericSort = (list, key, ascending, customOrder) => {
let sorted
if (customOrder) {
sorted = list.sort((a, b) => {
const aValue = a.result.toLowerCase()
const bValue = b.result.toLowerCase()
const aIndex = customOrder.findIndex((item) => item.toLowerCase() === aValue)
const bIndex = customOrder.findIndex((item) => item.toLowerCase() === bValue)
// Compare the indices to determine the sort order
return aIndex - bIndex
})
} else {
sorted = list.sort((a, b) => a[key] === b[key] ? 0 : a[key] > b[key] ? 1 : -1)
}
if (ascending) {
sorted.reverse()
}
return sorted
}
const durationSort = (list, ascending) => {
const parseDuration = (duration) => {
if (duration.includes(':')) {
// If it's in the format "HH:mm:ss"
const [hours, minutes, seconds] = duration.split(':').map(Number)
return (hours * 3600 + minutes * 60 + seconds) * 1000
} else {
// If it's in the format "nnn ms"
return parseInt(duration)
}
}
const sorted = list.sort((a, b) => parseDuration(a['duration']) - parseDuration(b['duration']))
if (ascending) {
sorted.reverse()
}
return sorted
}
const doInitSort = () => {
const type = storageModule.getSort(manager.initialSort)
const ascending = storageModule.getSortDirection()
const list = manager.testSubset
const initialOrder = ['Error', 'Failed', 'Rerun', 'XFailed', 'XPassed', 'Skipped', 'Passed']
storageModule.setSort(type)
storageModule.setSortDirection(ascending)
if (type?.toLowerCase() === 'original') {
manager.setRender(list)
} else {
let sortedList
switch (type) {
case 'duration':
sortedList = durationSort(list, ascending)
break
case 'result':
sortedList = genericSort(list, type, ascending, initialOrder)
break
default:
sortedList = genericSort(list, type, ascending)
break
}
manager.setRender(sortedList)
}
}
const doSort = (type, skipDirection) => {
const newSortType = storageModule.getSort(manager.initialSort) !== type
const currentAsc = storageModule.getSortDirection()
let ascending
if (skipDirection) {
ascending = currentAsc
} else {
ascending = newSortType ? false : !currentAsc
}
storageModule.setSort(type)
storageModule.setSortDirection(ascending)
const list = manager.testSubset
const sortedList = type === 'duration' ? durationSort(list, ascending) : genericSort(list, type, ascending)
manager.setRender(sortedList)
}
module.exports = {
doInitSort,
doSort,
}
},{"./datamanager.js":1,"./storage.js":8}],8:[function(require,module,exports){
const possibleFilters = [
'passed',
'skipped',
'failed',
'error',
'xfailed',
'xpassed',
'rerun',
]
const getVisible = () => {
const url = new URL(window.location.href)
const settings = new URLSearchParams(url.search).get('visible')
const lower = (item) => {
const lowerItem = item.toLowerCase()
if (possibleFilters.includes(lowerItem)) {
return lowerItem
}
return null
}
return settings === null ?
possibleFilters :
[...new Set(settings?.split(',').map(lower).filter((item) => item))]
}
const hideCategory = (categoryToHide) => {
const url = new URL(window.location.href)
const visibleParams = new URLSearchParams(url.search).get('visible')
const currentVisible = visibleParams ? visibleParams.split(',') : [...possibleFilters]
const settings = [...new Set(currentVisible)].filter((f) => f !== categoryToHide).join(',')
url.searchParams.set('visible', settings)
window.history.pushState({}, null, unescape(url.href))
}
const showCategory = (categoryToShow) => {
if (typeof window === 'undefined') {
return
}
const url = new URL(window.location.href)
const currentVisible = new URLSearchParams(url.search).get('visible')?.split(',').filter(Boolean) ||
[...possibleFilters]
const settings = [...new Set([categoryToShow, ...currentVisible])]
const noFilter = possibleFilters.length === settings.length || !settings.length
noFilter ? url.searchParams.delete('visible') : url.searchParams.set('visible', settings.join(','))
window.history.pushState({}, null, unescape(url.href))
}
const getSort = (initialSort) => {
const url = new URL(window.location.href)
let sort = new URLSearchParams(url.search).get('sort')
if (!sort) {
sort = initialSort || 'result'
}
return sort
}
const setSort = (type) => {
const url = new URL(window.location.href)
url.searchParams.set('sort', type)
window.history.pushState({}, null, unescape(url.href))
}
const getCollapsedCategory = (renderCollapsed) => {
let categories
if (typeof window !== 'undefined') {
const url = new URL(window.location.href)
const collapsedItems = new URLSearchParams(url.search).get('collapsed')
switch (true) {
case !renderCollapsed && collapsedItems === null:
categories = ['passed']
break
case collapsedItems?.length === 0 || /^["']{2}$/.test(collapsedItems):
categories = []
break
case /^all$/.test(collapsedItems) || collapsedItems === null && /^all$/.test(renderCollapsed):
categories = [...possibleFilters]
break
default:
categories = collapsedItems?.split(',').map((item) => item.toLowerCase()) || renderCollapsed
break
}
} else {
categories = []
}
return categories
}
const getSortDirection = () => JSON.parse(sessionStorage.getItem('sortAsc')) || false
const setSortDirection = (ascending) => sessionStorage.setItem('sortAsc', ascending)
const getCollapsedIds = () => JSON.parse(sessionStorage.getItem('collapsedIds')) || []
const setCollapsedIds = (list) => sessionStorage.setItem('collapsedIds', JSON.stringify(list))
module.exports = {
getVisible,
hideCategory,
showCategory,
getCollapsedIds,
setCollapsedIds,
getSort,
setSort,
getSortDirection,
setSortDirection,
getCollapsedCategory,
possibleFilters,
}
},{}]},{},[4]);
</script>
</footer>
</html>
\ No newline at end of file
2023-11-06 11:28:15 - test_bpm_laohuang.py[line:61] - ERROR: 断言失败,用例数据为:{'password': 'MTIzNDU2', 'username': 'admin'},期望数据为:{'username': '超级管理', 'account': 'admin', 'loginStatus': True},服务器返回的数据为:{"token":"eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiJhZG1pbiIsInRlbmFudElkIjoiLTEiLCJleHAiOjE2OTkzMjc2OTYsImlhdCI6MTY5OTI0MTI5Nn0.Xn3s7eqjuBBGRSai3BCwNTsou6eNV4eLfhpJSuWHrh32X2AbghJ_4QsnGiXg7tKWPnhWqwt3SVzklCLByZ2vYg","username":"超级管理员","account":"admin","userId":"1","expiration":86400,"loginStatus":true,"userAttrs":{"tenantId":"-1"}}
2023-11-06 11:28:15 - test_bpm_laohuang.py[line:61] - ERROR: 断言失败,用例数据为:{'password': 'MTIzNDU2', 'username': 'admin'},期望数据为:{'username': '超级管理', 'account': 'admin', 'loginStatus': True},服务器返回的数据为:{"token":"eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiJhZG1pbiIsInRlbmFudElkIjoiLTEiLCJleHAiOjE2OTkzMjc2OTYsImlhdCI6MTY5OTI0MTI5Nn0.Xn3s7eqjuBBGRSai3BCwNTsou6eNV4eLfhpJSuWHrh32X2AbghJ_4QsnGiXg7tKWPnhWqwt3SVzklCLByZ2vYg","username":"超级管理员","account":"admin","userId":"1","expiration":86400,"loginStatus":true,"userAttrs":{"tenantId":"-1"}}
2023-11-06 11:28:18 - test_bpm_laohuang.py[line:61] - ERROR: 断言失败,用例数据为:{'password': 'MTIzNDU2', 'username': 'admin'},期望数据为:{'username': '超级管理', 'account': 'admin', 'loginStatus': True},服务器返回的数据为:{"token":"eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiJhZG1pbiIsInRlbmFudElkIjoiLTEiLCJleHAiOjE2OTkzMjc2OTksImlhdCI6MTY5OTI0MTI5OX0.vlFuJ9jl2d_0k74dae_QQ4CH0qy_3hl1EbylwL7RnokYU0DjbeV9De_KE6k8Bz3i6a3zqCSgkj6-APjxO57Q7w","username":"超级管理员","account":"admin","userId":"1","expiration":86400,"loginStatus":true,"userAttrs":{"tenantId":"-1"}}
2023-11-06 11:28:20 - test_bpm_laohuang.py[line:61] - ERROR: 断言失败,用例数据为:{'password': 'MTIzNDU2', 'username': 'admin'},期望数据为:{'username': '超级管理', 'account': 'admin', 'loginStatus': True},服务器返回的数据为:{"token":"eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiJhZG1pbiIsInRlbmFudElkIjoiLTEiLCJleHAiOjE2OTkzMjc3MDEsImlhdCI6MTY5OTI0MTMwMX0.-rBNLVLLkh-FYtTyF07nWpev9OgwpGi8BI6qcdvJmZWSuXM4Kf2dEKb6MvOrJzhdkynWhUoXNHK2HiiPOkTB5Q","username":"超级管理员","account":"admin","userId":"1","expiration":86400,"loginStatus":true,"userAttrs":{"tenantId":"-1"}}
2023-11-06 11:28:22 - test_bpm_laohuang.py[line:61] - ERROR: 断言失败,用例数据为:{'password': 'MTIzNDU2', 'username': 'admin'},期望数据为:{'username': '超级管理', 'account': 'admin', 'loginStatus': True},服务器返回的数据为:{"token":"eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiJhZG1pbiIsInRlbmFudElkIjoiLTEiLCJleHAiOjE2OTkzMjc3MDMsImlhdCI6MTY5OTI0MTMwM30.najrgfkyREASF7s-L3iewvKRdx9Uisw1vAQaGaiqMR-xSo4-kqkiORymDmAN_RkNn8WmnPheN_Wn16bsp5cbXA","username":"超级管理员","account":"admin","userId":"1","expiration":86400,"loginStatus":true,"userAttrs":{"tenantId":"-1"}}
2023-11-06 11:28:24 - test_bpm_laohuang.py[line:61] - ERROR: 断言失败,用例数据为:{'password': 'MTIzNDU2', 'username': 'admin'},期望数据为:{'username': '超级管理', 'account': 'admin', 'loginStatus': True},服务器返回的数据为:{"token":"eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiJhZG1pbiIsInRlbmFudElkIjoiLTEiLCJleHAiOjE2OTkzMjc3MDUsImlhdCI6MTY5OTI0MTMwNX0._wZM3DPeDm6rP3ZB4WxTQe0GfuetaGPyTCfbcsUsKDTxE9ov3EbJ6mcK__HyLvWl72IvREhrawD3QYCQaNm6aQ","username":"超级管理员","account":"admin","userId":"1","expiration":86400,"loginStatus":true,"userAttrs":{"tenantId":"-1"}}
2023-11-06 11:28:26 - test_bpm_laohuang.py[line:61] - ERROR: 断言失败,用例数据为:{'password': 'MTIzNDU2', 'username': 'admin'},期望数据为:{'username': '超级管理', 'account': 'admin', 'loginStatus': True},服务器返回的数据为:{"token":"eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiJhZG1pbiIsInRlbmFudElkIjoiLTEiLCJleHAiOjE2OTkzMjc3MDcsImlhdCI6MTY5OTI0MTMwN30.Uf_I-51XxOBHebUk1JADsqxPWHo_azhspVbOC2x71LgjCwclk4_qtfDGko-_VKJOXXzdEVGgcJYDCRg7XA2CpA","username":"超级管理员","account":"admin","userId":"1","expiration":86400,"loginStatus":true,"userAttrs":{"tenantId":"-1"}}
2023-11-06 11:28:27 - test_bpm_laohuang.py[line:61] - ERROR: 断言失败,用例数据为:None,期望数据为:{'message': '刷新成功'},服务器返回的数据为:{"token":"eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiJhZG1pbiIsInRlbmFudElkIjoiLTEiLCJleHAiOjE2OTkzMjc3MDgsImlhdCI6MTY5OTI0MTMwOH0.ezGLR_w5Fp6Gq6Q9mrEAim12WeKeAtKq_HJoyCMZXle_rCC5le3f873GLfRC6jNtZOcLldBH05CfExJ4RwmnyQ","username":"","account":"","userId":"","loginStatus":true,"userAttrs":{}}
2023-11-06 11:28:29 - test_bpm_laohuang.py[line:61] - ERROR: 断言失败,用例数据为:None,期望数据为:{'message': '刷新成功'},服务器返回的数据为:{"token":"eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiJhZG1pbiIsInRlbmFudElkIjoiLTEiLCJleHAiOjE2OTkzMjc3MTAsImlhdCI6MTY5OTI0MTMxMH0.gbRbou24K4DowK5MFO-KuALkDCzcxCtyXMLFWpAgaKzMwt-JNDrBhOmrkRMKaEf7cxlZ4mZKxsrRckFDFuVeAA","username":"","account":"","userId":"","loginStatus":true,"userAttrs":{}}
2023-11-06 11:28:31 - test_bpm_laohuang.py[line:61] - ERROR: 断言失败,用例数据为:None,期望数据为:{'message': '刷新成功'},服务器返回的数据为:{"token":"eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiJhZG1pbiIsInRlbmFudElkIjoiLTEiLCJleHAiOjE2OTkzMjc3MTIsImlhdCI6MTY5OTI0MTMxMn0.SgpBpzWFUoXY67IcejMivM7-929nOofIdAawNmpg8IpRmaa0XS4ZwXCcumoYm7SZYhQ9HwgClpqiZMr5ypA6ug","username":"","account":"","userId":"","loginStatus":true,"userAttrs":{}}
2023-11-06 11:28:33 - test_bpm_laohuang.py[line:61] - ERROR: 断言失败,用例数据为:None,期望数据为:{'message': '刷新成功'},服务器返回的数据为:{"token":"eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiJhZG1pbiIsInRlbmFudElkIjoiLTEiLCJleHAiOjE2OTkzMjc3MTQsImlhdCI6MTY5OTI0MTMxNH0.glQ2NxH0Cx7IaznqCdy6iCzR1CF23n9Kc4t_WioERwC2MgVoAv-4-Z7tjMQVkMdwSkwYCwRna_y69d83N3q63g","username":"","account":"","userId":"","loginStatus":true,"userAttrs":{}}
2023-11-06 11:28:36 - test_bpm_laohuang.py[line:61] - ERROR: 断言失败,用例数据为:None,期望数据为:{'message': '刷新成功'},服务器返回的数据为:{"token":"eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiJhZG1pbiIsInRlbmFudElkIjoiLTEiLCJleHAiOjE2OTkzMjc3MTYsImlhdCI6MTY5OTI0MTMxNn0.xfPbrROYSAqpJP-UNuhfrZ7_1fmY4vHXt_1BOesc10oimWGIO86xejGNYbre3sG12UGuDrJVseKKHmlwpcjVsA","username":"","account":"","userId":"","loginStatus":true,"userAttrs":{}}
2023-11-06 11:28:38 - test_bpm_laohuang.py[line:61] - ERROR: 断言失败,用例数据为:None,期望数据为:{'message': '刷新成功'},服务器返回的数据为:{"token":"eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiJhZG1pbiIsInRlbmFudElkIjoiLTEiLCJleHAiOjE2OTkzMjc3MTgsImlhdCI6MTY5OTI0MTMxOH0.LIwousKPqbvOt9_rkLIzVJZnisd7bqQUDL0qWwbgmZrV7lBTOB_bzwTNlLT0QATsNHLQPvu03AZ-FmQ4x-69YQ","username":"","account":"","userId":"","loginStatus":true,"userAttrs":{}}
2023-11-06 11:28:38 - test_bpm_laohuang.py[line:61] - ERROR: 断言失败,用例数据为:{'ids': '1721368972332384256'},期望数据为:{'state': True, 'message': '删除维度成功'},服务器返回的数据为:{"state":true,"message":"删除维度成功!","value":""}
2023-11-06 11:28:40 - test_bpm_laohuang.py[line:61] - ERROR: 断言失败,用例数据为:{'ids': '1721368972332384256'},期望数据为:{'state': True, 'message': '删除维度成功'},服务器返回的数据为:{"state":false,"message":"","logId":"1721368983254351872"}
2023-11-06 11:28:43 - test_bpm_laohuang.py[line:61] - ERROR: 断言失败,用例数据为:{'ids': '1721368972332384256'},期望数据为:{'state': True, 'message': '删除维度成功'},服务器返回的数据为:{"state":false,"message":"","logId":"1721368992360185856"}
2023-11-06 11:28:45 - test_bpm_laohuang.py[line:61] - ERROR: 断言失败,用例数据为:{'ids': '1721368972332384256'},期望数据为:{'state': True, 'message': '删除维度成功'},服务器返回的数据为:{"state":false,"message":"","logId":"1721369001419882496"}
2023-11-06 11:28:47 - test_bpm_laohuang.py[line:61] - ERROR: 断言失败,用例数据为:{'ids': '1721368972332384256'},期望数据为:{'state': True, 'message': '删除维度成功'},服务器返回的数据为:{"state":false,"message":"","logId":"1721369010613796864"}
2023-11-06 11:28:49 - test_bpm_laohuang.py[line:61] - ERROR: 断言失败,用例数据为:{'ids': '1721368972332384256'},期望数据为:{'state': True, 'message': '删除维度成功'},服务器返回的数据为:{"state":false,"message":"","logId":"1721369019694465024"}
2023-11-06 11:28:50 - test_bpm.py[line:59] - ERROR: 断言失败,用例数据为:{'password': 'MTIzNDU2', 'username': 'admin'},期望数据为:{'username': '超级管理', 'account': 'admin', 'loginStatus': True},服务器返回的数据为:{"token":"eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiJhZG1pbiIsInRlbmFudElkIjoiLTEiLCJleHAiOjE2OTkzMjc3MzEsImlhdCI6MTY5OTI0MTMzMX0.GU7fcCf68Y2wWyzCPbuIrx_eut3nZvuUxE-xqfC7ETDw8HhMhnpsjnY4P4LOtkxp9LgLcEd9hjt_q1a2I4c4GQ","username":"超级管理员","account":"admin","userId":"1","expiration":86400,"loginStatus":true,"userAttrs":{"tenantId":"-1"}}
2023-11-06 11:28:52 - test_bpm.py[line:59] - ERROR: 断言失败,用例数据为:{'password': 'MTIzNDU2', 'username': 'admin'},期望数据为:{'username': '超级管理', 'account': 'admin', 'loginStatus': True},服务器返回的数据为:{"token":"eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiJhZG1pbiIsInRlbmFudElkIjoiLTEiLCJleHAiOjE2OTkzMjc3MzMsImlhdCI6MTY5OTI0MTMzM30.Yuj9-BKCSwKe9o6WmGCCUNZqVqsJukgxXGDfF8LOg3YKJaAU0_wQEnItCvTHtksWHTUm42gZ9YWVyC5w2WGkYQ","username":"超级管理员","account":"admin","userId":"1","expiration":86400,"loginStatus":true,"userAttrs":{"tenantId":"-1"}}
2023-11-06 11:28:54 - test_bpm.py[line:59] - ERROR: 断言失败,用例数据为:{'password': 'MTIzNDU2', 'username': 'admin'},期望数据为:{'username': '超级管理', 'account': 'admin', 'loginStatus': True},服务器返回的数据为:{"token":"eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiJhZG1pbiIsInRlbmFudElkIjoiLTEiLCJleHAiOjE2OTkzMjc3MzUsImlhdCI6MTY5OTI0MTMzNX0.1Ubnafj-7G3rCENRJUQNRxxzlVN_NU_cLTdh6w5LHywUaHtM2021AYLp6uLnbc0o-tEZimClpRp4C8XngP4vmA","username":"超级管理员","account":"admin","userId":"1","expiration":86400,"loginStatus":true,"userAttrs":{"tenantId":"-1"}}
2023-11-06 11:28:56 - test_bpm.py[line:59] - ERROR: 断言失败,用例数据为:{'password': 'MTIzNDU2', 'username': 'admin'},期望数据为:{'username': '超级管理', 'account': 'admin', 'loginStatus': True},服务器返回的数据为:{"token":"eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiJhZG1pbiIsInRlbmFudElkIjoiLTEiLCJleHAiOjE2OTkzMjc3MzcsImlhdCI6MTY5OTI0MTMzN30.vrKaXuH45etiu-vbsjISFiHVMng6A5s9BzBCZul8EbmGDURFu8XS7eY_UHlm3GiDi6gdOFic16423it7DSlyIg","username":"超级管理员","account":"admin","userId":"1","expiration":86400,"loginStatus":true,"userAttrs":{"tenantId":"-1"}}
2023-11-06 11:28:58 - test_bpm.py[line:59] - ERROR: 断言失败,用例数据为:{'password': 'MTIzNDU2', 'username': 'admin'},期望数据为:{'username': '超级管理', 'account': 'admin', 'loginStatus': True},服务器返回的数据为:{"token":"eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiJhZG1pbiIsInRlbmFudElkIjoiLTEiLCJleHAiOjE2OTkzMjc3MzksImlhdCI6MTY5OTI0MTMzOX0.KAbgSxRcywZF9Tsk4Sx4iOgMPaGhVBAPxaeCy57cZ2-HaexggOMIVA0bZYvqWLOQ14hdGnVCv03obM5Gn2_i-g","username":"超级管理员","account":"admin","userId":"1","expiration":86400,"loginStatus":true,"userAttrs":{"tenantId":"-1"}}
2023-11-06 11:29:00 - test_bpm.py[line:59] - ERROR: 断言失败,用例数据为:{'password': 'MTIzNDU2', 'username': 'admin'},期望数据为:{'username': '超级管理', 'account': 'admin', 'loginStatus': True},服务器返回的数据为:{"token":"eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiJhZG1pbiIsInRlbmFudElkIjoiLTEiLCJleHAiOjE2OTkzMjc3NDEsImlhdCI6MTY5OTI0MTM0MX0.RhslVcBPdTOQBotq5eqNssdsWUwWGt03ftbThwr4JJQCc6LHkm_eNL_fOr7xEFMMKlEIsFFi7Rj0H6O1QDhN1w","username":"超级管理员","account":"admin","userId":"1","expiration":86400,"loginStatus":true,"userAttrs":{"tenantId":"-1"}}
2023-11-06 11:29:01 - test_bpm.py[line:59] - ERROR: 断言失败,用例数据为:None,期望数据为:{'message': '刷新成功'},服务器返回的数据为:{"token":"eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiJhZG1pbiIsInRlbmFudElkIjoiLTEiLCJleHAiOjE2OTkzMjc3NDIsImlhdCI6MTY5OTI0MTM0Mn0.k3G_x51J0uUfLIhsK75_p7kQJ4oRERdnEKmvjPSO8u54EgDLRS1ausCDa4IGa3ZWYQDqe17XXcK0_ZFxIaoxbA","username":"","account":"","userId":"","loginStatus":true,"userAttrs":{}}
2023-11-06 11:29:03 - test_bpm.py[line:59] - ERROR: 断言失败,用例数据为:None,期望数据为:{'message': '刷新成功'},服务器返回的数据为:{"token":"eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiJhZG1pbiIsInRlbmFudElkIjoiLTEiLCJleHAiOjE2OTkzMjc3NDQsImlhdCI6MTY5OTI0MTM0NH0.IQvmGek4a7cF0D8CHTh927O6Ao1Pde5BQXxeX-7pUHechWiJhJFJZfP441j74Fg2qlp03MfiY39DtfT5F3R9EQ","username":"","account":"","userId":"","loginStatus":true,"userAttrs":{}}
2023-11-06 11:29:05 - test_bpm.py[line:59] - ERROR: 断言失败,用例数据为:None,期望数据为:{'message': '刷新成功'},服务器返回的数据为:{"token":"eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiJhZG1pbiIsInRlbmFudElkIjoiLTEiLCJleHAiOjE2OTkzMjc3NDYsImlhdCI6MTY5OTI0MTM0Nn0.DIRxCXllFPB1gNGOSW3EWBFiU3b1HLJR-0dLVXbBe8gCtNTfZnGA25Y5RNCJ-ODzJ3bSWNjnOFBjD3XmjgoY7g","username":"","account":"","userId":"","loginStatus":true,"userAttrs":{}}
2023-11-06 11:29:07 - test_bpm.py[line:59] - ERROR: 断言失败,用例数据为:None,期望数据为:{'message': '刷新成功'},服务器返回的数据为:{"token":"eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiJhZG1pbiIsInRlbmFudElkIjoiLTEiLCJleHAiOjE2OTkzMjc3NDgsImlhdCI6MTY5OTI0MTM0OH0.0puy-AV928ylbB9JECIZzX1lOuroYBTDgdY9WADYfdaXssbxM1Zzjh4XFIdKYYOOgGtwxsxPaUsbw9wKnIcatg","username":"","account":"","userId":"","loginStatus":true,"userAttrs":{}}
2023-11-06 11:29:09 - test_bpm.py[line:59] - ERROR: 断言失败,用例数据为:None,期望数据为:{'message': '刷新成功'},服务器返回的数据为:{"token":"eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiJhZG1pbiIsInRlbmFudElkIjoiLTEiLCJleHAiOjE2OTkzMjc3NTAsImlhdCI6MTY5OTI0MTM1MH0.Yfrret163NiqN_tC0-vXuiv_3FLZTHIfw6-lQOKVZd61qtRge6H4pdryCUBe4t6yEAX49CeVlBtf6VCltySpkQ","username":"","account":"","userId":"","loginStatus":true,"userAttrs":{}}
2023-11-06 11:29:12 - test_bpm.py[line:59] - ERROR: 断言失败,用例数据为:None,期望数据为:{'message': '刷新成功'},服务器返回的数据为:{"token":"eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiJhZG1pbiIsInRlbmFudElkIjoiLTEiLCJleHAiOjE2OTkzMjc3NTIsImlhdCI6MTY5OTI0MTM1Mn0.UPH9TxHGQjX4RCh-3A1v_mzoRb4CXw27nzrlQMDj0iV16TvWouJmOu7sYpLMf8qLFrDcz0lE8-wTdLZ-fe1A4A","username":"","account":"","userId":"","loginStatus":true,"userAttrs":{}}
2023-11-06 11:29:12 - test_bpm.py[line:59] - ERROR: 断言失败,用例数据为:{'ids': '1721369114598981632'},期望数据为:{'state': True, 'message': '删除维度成功'},服务器返回的数据为:{"state":true,"message":"删除维度成功!","value":""}
2023-11-06 11:29:14 - test_bpm.py[line:59] - ERROR: 断言失败,用例数据为:{'ids': '1721369114598981632'},期望数据为:{'state': True, 'message': '删除维度成功'},服务器返回的数据为:{"state":false,"message":"","logId":"1721369125588058112"}
2023-11-06 11:29:16 - test_bpm.py[line:59] - ERROR: 断言失败,用例数据为:{'ids': '1721369114598981632'},期望数据为:{'state': True, 'message': '删除维度成功'},服务器返回的数据为:{"state":false,"message":"","logId":"1721369134714863616"}
2023-11-06 11:29:19 - test_bpm.py[line:59] - ERROR: 断言失败,用例数据为:{'ids': '1721369114598981632'},期望数据为:{'state': True, 'message': '删除维度成功'},服务器返回的数据为:{"state":false,"message":"","logId":"1721369143862640640"}
2023-11-06 11:29:21 - test_bpm.py[line:59] - ERROR: 断言失败,用例数据为:{'ids': '1721369114598981632'},期望数据为:{'state': True, 'message': '删除维度成功'},服务器返回的数据为:{"state":false,"message":"","logId":"1721369152922337280"}
2023-11-06 11:29:23 - test_bpm.py[line:59] - ERROR: 断言失败,用例数据为:{'ids': '1721369114598981632'},期望数据为:{'state': True, 'message': '删除维度成功'},服务器返回的数据为:{"state":false,"message":"","logId":"1721369162053337088"}
This source diff could not be displayed because it is too large. You can view the blob instead.
# -*-coding:utf-8 -*- #
# ---------------------------------------------------------------------------
# ProjectName: test_57
# FileName: __init__.py
# Author: xxxxxxx
# Datetime: 2023/11/3 14:01
# Description:
#
# ---------------------------------------------------------------------------
# -*-coding:utf-8 -*- #
# ---------------------------------------------------------------------------
# ProjectName: test_57
# FileName: requests_method.py
# Author: xxxxxxx
# Datetime: 2023/11/3 15:24
# Description:
#
# ---------------------------------------------------------------------------
import base64
import logging
import requests
from InterfaceAutoTest.common import log
from InterfaceAutoTest.common.read_ini import ReadIni
from InterfaceAutoTest.data_config.settings import *
class RequestsMethod:
def __init__(self):
"""关联被测系统的登录状态"""
login_url = ReadIni().get_host(URL_HOST_CUSTOM) + "/auth"
login_data = {"username": "admin", "password": base64.b64encode("123456".encode()).decode()}
self.bpm_session = requests.sessions.Session()
self.bpm_session.headers.update({"Authorization": "Bearer "+self.bpm_session.post(url=login_url, json=login_data).json().get("token")})
def request_all(self, req_method, req_url, req_mime=None, case_data=None):
"""封装公共的请求方法"""
if req_mime == "json" or req_mime == "application/json":
return self.bpm_session.request(method=req_method, url=req_url, json=case_data)
elif req_mime == "x-www-form-urlencoded" or req_mime == "application/x-www-form-urlencoded":
return self.bpm_session.request(method=req_method, url=req_url, data=case_data)
elif req_mime == "form-data" or req_mime == "multipart/form-data":
return self.bpm_session.request(method=req_method, url=req_url, files=case_data)
elif req_mime == "query" or req_mime == "params" or req_mime == "param":
return self.bpm_session.request(method=req_method, url=req_url, params=case_data)
elif req_mime is None:
return self.bpm_session.request(method=req_method, url=req_url)
# 判断媒体类型是否为query|body 或者 body|query 、json|query、query|json
elif req_mime == "query|body" or req_mime == "body|query" or req_mime == "json|query" or req_mime == "query|json":
return self.bpm_session.request(method=req_method, url=req_url, params=case_data["query"], json=case_data["body"])
else:
log.error("传入的媒体类型的值错误,请察看excel中是否填入正确")
raise NameError("传入的媒体类型的值错误,请察看excel中是否填入正确")
\ No newline at end of file
# -*-coding:utf-8 -*- #
# ---------------------------------------------------------------------------
# ProjectName: test_57
# FileName: __init__.py
# Author: xxxxxxx
# Datetime: 2023/11/3 14:01
# Description:
#
# ---------------------------------------------------------------------------
[pytest]
;开启日志
;log_cli=true
;设置日志的级别,如果不设置级别的话,可以设置为NOTSET,如果要设置级别,级别可以有debug,info,warning,error,致命
;log_level=NOTSET
;设置日志显示的信息格式
;log_format=%(asctime)s - %(filename)s[line:%(lineno)d] - %(levelname)s: %(message)s
;设置日志中时间显示的格式
;log_date_format=%Y-%m-%d %H:%M:%S
;每个py文件运行的时候追加的命令
;addopts=-vs
;设置日志保存的文件
log_file=./report/log/bpm_接口自动化框架最新运行日志.log
;设置日志保存在文件中的级别
log_file_level=error
;设置日志在文件中的信息格式
log_file_format=%(asctime)s - %(filename)s[line:%(lineno)d] - %(levelname)s: %(message)s
;设置文件日志中时间显示的格式
log_file_date_format=%Y-%m-%d %H:%M:%S
\ No newline at end of file
# -*-coding:utf-8 -*- #
# ---------------------------------------------------------------------------
# ProjectName: test_57
# FileName: __init__.py
# Author: xxxxxxx
# Datetime: 2023/11/3 17:37
# Description:
#
# ---------------------------------------------------------------------------
# -*-coding:utf-8 -*- #
# ---------------------------------------------------------------------------
# ProjectName: test_57
# FileName: conftest.py
# Author: xxxxxxx
# Datetime: 2023/11/3 15:33
# Description:
#
# ---------------------------------------------------------------------------
import pytest
from InterfaceAutoTest.common.db import DB
from InterfaceAutoTest.requests_method.requests_method import RequestsMethod
@pytest.fixture(scope="session")
def req_fix():
req = RequestsMethod()
yield req
@pytest.fixture(scope="session")
def db_fix():
db = DB()
yield db
db.close()
# 黄总定义的自定义固件,请勿乱动=================start=========>
# <====================================================end
def pytest_collection_modifyitems(items):
# item表示每个测试用例,解决用例名称中文显示问题
for item in items:
item.name = item.name.encode("utf-8").decode("unicode-escape")
item._nodeid = item._nodeid.encode("utf-8").decode("unicode-escape")
# -*-coding:utf-8 -*- #
# ---------------------------------------------------------------------------
# ProjectName: test_57
# FileName: test_bpm.py
# Author: xxxxxxx
# Datetime: 2023/11/3 15:33
# Description:
#
# ---------------------------------------------------------------------------
import pytest
from InterfaceAutoTest.common import log
from InterfaceAutoTest.common.read_excel import ReadExcel
import allure
class TestBPM:
@allure.epic("BPM项目-老黄")
# @allure.feature("模块名称")
# @allure.story("接口名称")
# @allure.title("用例标题")
# @allure.severity("用例等级")
@pytest.mark.parametrize("module_name, api_name, title, level, case_url, case_method, case_mime, case_data, "
"expect_data, sql_type, sql_data, update_key", ReadExcel("BPM-laohuang").get_data())
def test_bpm(self, db_fix, req_fix, module_name, api_name, title, level, case_url, case_method, case_mime,
case_data, expect_data, sql_type, sql_data, update_key):
# 影响allure报告的数据,不影响代码流程
allure.dynamic.feature(module_name)
allure.dynamic.story(api_name)
allure.dynamic.title(title)
allure.dynamic.severity(level)
# 判断sql语句的类型是否为delete
if sql_type == "delete":
# 使用DB类对象执行删除的sql语句
db_fix.delete(sql_data)
# 使用RequestsMethod类对象发送请求--pass
# 判断sql语句类型是否为select
elif sql_type == "select":
# 使用DB类对象执行查询的sql语句,并接收查询的结果
select_result = db_fix.select(sql_data)
# 将查询结果更新到用例数据中
case_data[update_key] = select_result
# 使用RequestsMethod类对象发送请求--pass
# 判断sql语句的类型是否为select|delete或者为delete|select
elif sql_type == "select|delete" or sql_type == "delete|select":
# 使用DB类对象执行删除的sql语句
db_fix.delete(sql_data.get("delete"))
# 使用DB类对象执行查询的sql语句,并接收查询的结果
select_result = db_fix.select(sql_data.get("select"))
# 将查询结果更新到用例数据中
case_data[update_key] = select_result
# 使用RequestsMethod类对象发送请求
res = req_fix.request_all(req_method=case_method, req_url=case_url, req_mime=case_mime, case_data=case_data)
# 断言
try:
for key in expect_data:
assert expect_data[key] == res.json().get(key)
except:
log.error("断言失败"+",用例数据为:"+str(case_data)+",期望数据为:"+str(expect_data)+",服务器返回的数据为:"+res.text)
raise AssertionError("断言失败")
if __name__ == '__main__':
pytest.main()
\ No newline at end of file
# -*-coding:utf-8 -*- #
# ---------------------------------------------------------------------------
# ProjectName: test_57
# FileName: __init__.py
# Author: xxxxxxx
# Datetime: 2023/11/3 14:01
# Description:
#
# ---------------------------------------------------------------------------
# -*-coding:utf-8 -*- #
# ---------------------------------------------------------------------------
# ProjectName: test_57
# FileName: test_pytest_func.py
# Author: xxxxxxx
# Datetime: 2023/11/3 9:36
# Description:
#
# ---------------------------------------------------------------------------
import base64
import random
import pytest
import requests
import allure
"""
pytest装饰器:
1:@pytest.fixture(scope="指定自定义固件的级别", autouse=False, params=可迭代类型):实现自定义固件
2:@pytest.mark.parametrize("字符串", 可迭代类型): 实现用例的参数化
3: 下载插件,插件为:pytest-dependency, 下载方式为:pip install pytest-dependency
插件:pytest-dependency的功能为实现用例之间的依赖。
使用流程:
先使用装饰器@pytest.mark.dependency()标记依赖的用例
再使用装饰器@pytest.mark.dependency(depends=["用例的名称"])管理依赖的用例,也可以标记用例被后面的用例依赖
4: @pytest.mark.标签名:功能给用例打上标签,在终端运行的时候,使用的命令为:pytest -vs 用例py文件 -m="标签名"
5: @pytest.mark.run(order=num): num为整形,数字越小越先执行。但是需要下载插件,插件为:pip install pytest-ordering
6:@pytest.mark.usefixtures("自定义固件名称"):实现自定义固件的调用
7: @pytest.mark.skip(reason="无条件跳过"): 让用例无条件跳过
8: @pytest.mark.skipif(bool, reason="有条件跳过"):如果bool表达式为True,用例有条件跳过
9:@pytest.mark.xfail(reason="预期失败")
"""
dict1 = {}
@allure.epic("BPM_流程测试")
@allure.feature("认证接口和维度管理流程")
class Test01:
def setup_class(self):
login_url = "http://120.46.172.186:8080/auth"
# 配置登录数据
login_data = {"username": "admin", "password": base64.b64encode("123456".encode()).decode()}
self.bpm_sess = requests.sessions.Session()
self.token = self.bpm_sess.post(login_url, json=login_data).json().get("token")
self.bpm_sess.headers.update({"Authorization": "Bearer "+self.token})
@allure.story("登录")
@pytest.mark.dependency()
def test1(self):
print("用例1")
# 实现登录,获取服务器返回的token
login_url = "http://120.46.172.186:8080/auth"
# 配置登录数据
login_data = {"username": "admin", "password": base64.b64encode("123456".encode()).decode()}
res = self.bpm_sess.post(url=login_url, json=login_data)
print(res.text)
assert "超级管理员" == res.json().get("username")
@allure.story("添加维度")
@pytest.mark.dependency(depends=["Test01::test1"])
def test2(self):
print("添加维度用例")
add_dem_url = "http://120.46.172.186:8080/api/demension/v1/dem/addDem"
add_dem_data = {
"code": "addDem"+str(random.randrange(1, 100)),
"description": "addDem",
"isDefault": 0,
"name": "addDem"
}
res = self.bpm_sess.request(method="post", url=add_dem_url, json=add_dem_data)
print(res.text)
assert "添加维度成功" in res.text
@pytest.mark.dependency(depends=["test1", "test2"])
def test3(self):
print("用例3")
'''
@pytest.mark.run(order=4)
@pytest.mark.p1
def test1():
print("用例1")
@pytest.mark.dependency(depends=["test4"])
@pytest.mark.run(order=2)
@pytest.mark.p0
def test2():
print("用例2")
@pytest.mark.run(order=3)
@pytest.mark.p0
def test3():
print("用例3")
@pytest.mark.dependency()
@pytest.mark.run(order=1)
@pytest.mark.p1
def test4():
print("用例4")
assert 1 == 2
'''
'''
def test1():
print("用例1")
@pytest.mark.skip(reason="无条件跳过")
def test2():
print("用例2")
@pytest.mark.skipif(1 == 2, reason="无条件跳过")
def test3():
print("用例2")
@pytest.mark.xfail(reason="预期失败")
def test4():
print("预期失败")
assert 1 == 3
'''
if __name__ == '__main__':
pytest.main()
\ No newline at end of file
# -*-coding:utf-8 -*- #
# ---------------------------------------------------------------------------
# ProjectName: test_57
# FileName: __init__.py
# Author: xxxxxxx
# Datetime: 2023/11/3 17:38
# Description:
#
# ---------------------------------------------------------------------------
# -*-coding:utf-8 -*- #
# ---------------------------------------------------------------------------
# ProjectName: test_57
# FileName: conftest.py
# Author: xxxxxxx
# Datetime: 2023/11/3 15:33
# Description:
#
# ---------------------------------------------------------------------------
import pytest
from InterfaceAutoTest.common.db import DB
from InterfaceAutoTest.requests_method.requests_method import RequestsMethod
@pytest.fixture(scope="session")
def req_fix():
req = RequestsMethod()
yield req
@pytest.fixture(scope="session")
def db_fix():
db = DB()
yield db
db.close()
# 黄总定义的自定义固件,请勿乱动=================start=========>
# <====================================================end
def pytest_collection_modifyitems(items):
# item表示每个测试用例,解决用例名称中文显示问题
for item in items:
item.name = item.name.encode("utf-8").decode("unicode-escape")
item._nodeid = item._nodeid.encode("utf-8").decode("unicode-escape")
\ No newline at end of file
# -*-coding:utf-8 -*- #
# ---------------------------------------------------------------------------
# ProjectName: test_57
# FileName: test_bpm.py
# Author: xxxxxxx
# Datetime: 2023/11/3 15:33
# Description:
#
# ---------------------------------------------------------------------------
import pytest
from InterfaceAutoTest.common import log
from InterfaceAutoTest.common.read_excel import ReadExcel
from InterfaceAutoTest.common.read_ini import ReadIni
import allure
excel_path = ReadIni().get_file_path("excel")
class TestBPM:
@allure.epic("BPM_张三")
@pytest.mark.parametrize("module_name, api_name, title, level, case_url, case_method, case_mime, case_data, expect_data, sql_type, sql_data, update_key", ReadExcel("BPM", excel_path=excel_path).get_data())
def test_bpm(self, db_fix, req_fix, module_name, api_name, title, level, case_url, case_method, case_mime, case_data, expect_data, sql_type, sql_data, update_key):
allure.dynamic.feature(module_name)
allure.dynamic.story(api_name)
allure.dynamic.title(title)
allure.dynamic.severity(level)
# 判断sql语句的类型是否为delete
if sql_type == "delete":
# 使用DB类对象执行删除的sql语句
db_fix.delete(sql_data)
# 使用RequestsMethod类对象发送请求--pass
# 判断sql语句类型是否为select
elif sql_type == "select":
# 使用DB类对象执行查询的sql语句,并接收查询的结果
select_result = db_fix.select(sql_data)
# 将查询结果更新到用例数据中
case_data[update_key] = select_result
# 使用RequestsMethod类对象发送请求--pass
# 判断sql语句的类型是否为select|delete或者为delete|select
elif sql_type == "select|delete" or sql_type == "delete|select":
# 使用DB类对象执行删除的sql语句
db_fix.delete(sql_data.get("delete"))
# 使用DB类对象执行查询的sql语句,并接收查询的结果
select_result = db_fix.select(sql_data.get("select"))
# 将查询结果更新到用例数据中
case_data[update_key] = select_result
# 使用RequestsMethod类对象发送请求
res = req_fix.request_all(req_method=case_method, req_url=case_url, req_mime=case_mime, case_data=case_data)
# 断言
try:
for key in expect_data:
assert expect_data[key] == res.json().get(key)
except:
log.error("断言失败"+",用例数据为:"+str(case_data)+",期望数据为:"+str(expect_data)+",服务器返回的数据为:"+res.text)
raise AssertionError("断言失败")
if __name__ == '__main__':
pytest.main()
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment