create的js
//添加header的函数
function add_header() {
// 这里是动态拼接html语句,带着样式,拼凑成页面的 "key [] value []"
var html = '<div class="row">' +
'<div style="display: inline; width: 10%; margin-left: 10px; margin-right: 10px;" col-sm--2 col-md-2 col-lg-2>key</div>' +
'<div style="display: inline; width: 40%; margin-left: 10px; margin-right: 10px;" col-sm--4 col-md-4 col-lg-4><input class="h_key"></div>' +
'<div style="display: inline; width: 10%; margin-left: 10px; margin-right: 10px;" col-sm--2 col-md-2 col-lg-2>value</div>' +
'<div style="display: inline; width: 40%; margin-left: 10px; margin-right: 10px;" col-sm--4 col-md-4 col-lg-4><input class="h_value"></div>' +
'</div>'
$('#h_section').append(html); //把html代码加到id为h_section的元素下面
$('#h_section').show(); //展示此元素及刚刚加入的html代码
$('#c_section').show();
}
//添加param的函数
function add_param() {
// 这里是动态拼接html语句,带着样式,拼凑成页面的 "key [] value []"
var html = '<div class="row">' +
'<div style="display: inline; width: 10%; margin-left: 10px; margin-right: 10px;" col-sm--2 col-md-2 col-lg-2>key</div>' +
'<div style="display: inline; width: 40%; margin-left: 10px; margin-right: 10px;" col-sm--4 col-md-4 col-lg-4><input class="p_key"></div>' +
'<div style="display: inline; width: 10%; margin-left: 10px; margin-right: 10px;" col-sm--2 col-md-2 col-lg-2>value</div>' +
'<div style="display: inline; width: 40%; margin-left: 10px; margin-right: 10px;" col-sm--4 col-md-4 col-lg-4><input class="p_value"></div>' +
'</div>'
$('#p_section').append(html); //把html代码加到id为p_section的元素下面
$('#p_section').show(); //展示此元素及刚刚加入的html代码
$('#c_section').show();
}
//添加assert的函数
function add_assert() {
// 这里是动态拼接html语句,带着样式,拼凑成页面的 "jsonpath [] expect []"
var html = '<div class="row">' +
'<div style="display: inline; width: 10%; margin-left: 10px; margin-right: 10px;" col-sm--2 col-md-2 col-lg-2>jsonpath</div>' +
'<div style="display: inline; width: 40%; margin-left: 10px; margin-right: 10px;" col-sm--4 col-md-4 col-lg-4><input class="a_key"></div>' +
'<div style="display: inline; width: 10%; margin-left: 10px; margin-right: 10px;" col-sm--2 col-md-2 col-lg-2>expect</div>' +
'<div style="display: inline; width: 40%; margin-left: 10px; margin-right: 10px;" col-sm--4 col-md-4 col-lg-4><input class="a_value"></div>' +
'</div>'
$('#a_section').append(html); //把html代码加到id为a_section的元素下面
$('#a_section').show(); //展示此元素及刚刚加入的html代码
$('#c_section').show();
}
//提取参数
function get_parameter() {
//从页面上取需要的数据
var data = {
'method': $("#method").val(),
'host': $("#host").val(),
'header': {},
'params': {},
'assert': []
}
// 使用each函数遍历每一个header的key,按照each函数的索引
$('.h_key').each(function (index, element) {
// 分别取出header的key和value
var key = $('.h_key').eq(index).val();
var value = $('.h_value').eq(index).val();
data['header'][key] = value; //保存在data['header']
})
// 使用each函数遍历每一个parameter的key,按照each函数的索引
$('.p_key').each(function (index, element) {
// 分别取出parameter的key和value
var key = $('.p_key').eq(index).val();
var value = $('.p_value').eq(index).val();
data['params'][key] = value; //保存在data['param']
})
// jsonpath是断言的表达式,jsonpath结果与expect匹配,如果符合预期则成功,否则判定为失败。
// 使用each函数遍历每一个assert的jsonpath,按照each函数的索引
$('.a_key').each(function (index, element) {
//分别取出assert的jsonpath作为key和expect作为value
var key = $('.a_key').eq(index).val();
var value = $('.a_value').eq(index).val();
//保存在data['assert'],定义rule为key,expect为value
data['assert'].push({
'rule': key,
'expect': value
})
})
return data; //返回拿到的所有数据
}
//debug成功的处理函数
function debug_success(data) {
console.log(data);
// 先清空右侧的响应数据,否则append函数会不断累加结果。
$('#response').empty()
// 将返回的结果append到response区域,代码和json数据显示需要用pre与code标签,json.stringify使用参数null, 4缩进4个空格。
$('#response').append('<pre><code>' + JSON.stringify(data['data'], null, 4) + '</code></pre>')
alert(data['message']) //弹框提示后端返回的message信息
}
//debug事件处理函数
function send_request() {
// 这里要注意请求需要加蓝图的url_prefix即/interface
var url = host + '/interface/api/v1/debug';
var data = get_parameter();
http(url, data, 'POST', debug_success, fail); //请求后台的debug接口
}
//失败时同一处理,在console里面打印信息
function fail(data) {
console.log(data);
}
//保存成功的函数,弹框展示case_id
function save_success(data) {
console.log(data);
alert("保存用例成功,case_id" + data['data'])
}
//save事件处理函数
function save_request() {
// 这里要注意请求需要加蓝图的url_prefix即/interface
var url = host + '/interface/api/v1/save'; //请求后台的save接口
var data = get_parameter();
http(url, data, 'POST', save_success, fail);
}
//js入口
$(function () {
//初始化时隐藏指定id对应的元素
$('#h_section').hide();
$('#p_section').hide();
$('#a_section').hide();
$('#c_section').hide();
//指定id被点击时,调用对应的处理事件
$('#header').click(add_header);
$('#param').click(add_param);
$('#assert').click(add_assert);
$('#debug').click(send_request);
$('#save').click(save_request);
});
report的js,这里使用百度的echarts:https://echarts.baidu.com/examples/
// 画图函数,数据动态传入
function drawPie(id, data) {
var myChart = echarts.init(document.getElementById(id));
var option = {
backgroundColor: '#F5F5F5', //背景色
title: {
text: '测试统计数据',
x: 'center'
},
legend: {
orient: 'vertical',
x: 'left',
data: ['成功', '失败', '未检验']
},
color: ['#3c763d', '#a94442', '#0099CC'],
calculable: true,
series: [{
name: '测试结果',
type: 'pie',
radius: '55%',
center: ['50%', '60%'],
startAngle: 135,
data: [
{
value: data[0],
name: '成功',
itemStyle: {
normal: {
label: {
formatter: '{b} : {c} ({d}%)',
textStyle: {
align: 'left',
fontSize: 15,
}
},
labelLine: {
length: 40,
}
}
}
},
{
value: data[1],
name: '失败',
itemStyle: {
normal: {
label: {
formatter: '{b} : {c} ({d}%)',
textStyle: {
align: 'right',
fontSize: 15,
}
},
labelLine: {
length: 40,
}
}
}
},
{
value: data[2],
name: '未检验',
itemStyle: {
normal: {
label: {
formatter: '{b} : {c} ({d}%)',
textStyle: {
align: 'right',
fontSize: 15,
}
},
labelLine: {
length: 40,
}
}
}
}],
}]
};
// 为echarts对象加载数据
myChart.setOption(option);
}
function generate_table_detail(data, id) {
// 拼接table详细测试数据
var html = "";
for (var i = 0; i < data.length; i++) {
var slice = '<tr class="all">' +
'<td class="text-center">' + data[i]['_id'] + '</td>' +
'<td class="text-center">' + data[i]['host'] + '</td>' +
'<td class="text-center">' + data[i]['method'] + '</td>' +
'<td class="text-center">' + data[i]['status'] + '</td>' +
'<td class="text-center">' + data[i]['message'] + '</td>' +
'</tr>'
html = html + slice;
}
$('#' + id).append(html);
}
//成功的回调函数,由于后端返回的数据是list(result),所以这里取0的下标
function success(data) {
console.log(data)
var data = data['data']; //从返回数据中取出'data'的数据
$('#start').text(data[0]['time']['start']);
$('#end').text(data[0]['time']['end']);
$('#spend').text(data[0]['time']['cost']);
$('#total').text(data[0]['count']['total']);
$('#run').text(data[0]['count']['run']);
$('#skip').text(data[0]['count']['skip']);
//把数据传给前面写的drawPie()函数(画图函数)
drawPie('pie', [data[0]['count']['success'], data[0]['count']['fail'], data[0]['count']['skip']]);
$('#t-total').html(data[0]['count']['total']);
$('#t-success').html(data[0]['count']['success']);
$('#t-fail').html(data[0]['count']['fail']);
$('#t-skip').html(data[0]['count']['skip']);
// 筛选成功与失败的数据,还有跳过的数据
total = data[0]['result'];
success = [];
fail = [];
skip = [];
console.log(total)
for (var i = 0; i < total.length; i++) {
console.log(total[i]['message']);
if (total[i]['status'] == 0) {
success.push(total[i])
} else {
fail.push(total[i])
}
}
//分四次分别处理测试概要信息
generate_table_detail(total, 'panel-data-0');
generate_table_detail(success, 'panel-data-1');
generate_table_detail(fail, 'panel-data-2');
generate_table_detail(skip, 'panel-data-3');
}
//失败的回调函数
function fail(data) {
console.log(data)
}
// 入口函数
$(function () {
// 请求后端返回测试报告
// 测试报告通过url的最后一个字段(run_id)去取
var url = host + '/interface/api/v1/report'; //
var uri = window.location.href; //浏览器上的url
var slice = uri.split("/"); //把url根据/切割
var data = {
'id': slice[slice.length - 1] //拿切割后的最后一个数据,就是传进来的runid
};
http(url, data, 'POST', success, fail); //把runid发到后端处理
});
create的html
<!- 继承base ->
{% extends 'base.html' %}
<!- 声明需要的js ->
{% block script %}
<script src="/interface/static/create.js"></script>
{% endblock %}
<!- 页面内容 ->
{% block content %}
<!- 声明一个描点作为bootstrap容器 ->
<div class="container">
<!- 声明整个页面内容页为一行 ->
<div class="row">
<!- 将一行分为12列,左右各占6份,即均分为各占6份的两大列 ->
<div class="col-sm-12 col-md-6 col-lg-6">
<!- 声明左侧列请求方法的下拉框、url的输入框、增加header参数、param参数、断言参数的按钮为1行 ->
<div class="row">
<!- 选择请求方法的下拉框 ->
<select id="method">
<option value="get">get</option>
<option value="post">post</option>
<option value="put">put</option>
<option value="delete">delete</option>
</select>
<!- url的输入框、增加header参数、param参数、断言参数的按钮 ->
<input id="host" type="text" placeholder="http://www.baidu.cn">
<input id="header" type="button" value="header">
<input id="param" type="button" value="param">
<input id="assert" type="button" value="assert">
</div>
<!- 预留一个描点给后面js加header参数用,并且单独为一行 ->
<div id="h_section" class="row">
<hr>
<label>请求头</label>
</div>
<!- 预留一个描点给后面js加params参数用,并且单独为一行 ->
<div id="p_section" class="row">
<hr>
<label>请求参数</label>
</div>
<!- 预留一个描点给后面js加assert参数用,并且单独为一行 ->
<div id="a_section" class="row">
<hr>
<label>添加断言</label>
</div>
<!- 预留一个描点给后面js触发debug和save事件,并且声明这两个按钮为一行 ->
<div id="c_section" class="row">
<hr>
<input id="debug" type="button" value="debug">
<input id="save" type="button" value="save">
<hr>
</div>
</div>
<!- 右边大列(6小列),用于展示响应数据 ->
<div class="col-sm-12 col-md-6 col-lg-6">
<div id="response"></div>
</div>
</div>
</div>
{% endblock %}
report的html
{% extends 'base.html' %} <!- 继承base.html ->
{% block style %}
<style type="text/css" media="screen">
body {
margin: 0;
font-family: "Arial", "Microsoft YaHei", "黑体", "宋体", sans-serif;
font-size: 18px;
line-height: 1.5;
line-height: 1.5;
color: #333333;
}
.table {
margin-bottom: 1px;
width: 100%;
}
.hiddenRow {
display: none;
}
.container-fluid {
padding-right: 120px;
padding-left: 120px;
}
.nav-tabs li {
width: 186px;
text-align: center;
}
</style>
{% endblock %}
{% block script %}
<!- 从cdn引入echarts的js、interface蓝图下report的js ->
<script src="https://cdn.bootcss.com/echarts/4.1.0-release/echarts.min.js"></script>
<script src="/interface/static/report.js"></script>
<!- 展示测试结果详细信息 ->
<script>
function showClassDetail(detail_id, hiddenRow_id, class_type) {
console.log(document.getElementById(hiddenRow_id).className)
if ('详细' == document.getElementById(detail_id).innerText) {
if ('all' == class_type) {
document.getElementById(hiddenRow_id).className = 'all';
} else if ('success' == class_type) {
document.getElementById(hiddenRow_id).className = 'success';
} else if ('error' == class_type) {
document.getElementById(hiddenRow_id).className = 'error';
} else {
document.getElementById(hiddenRow_id).className = 'untreaded';
}
document.getElementById(detail_id).innerText = "收起"
} else {
document.getElementById(detail_id).innerText = "详细"
document.getElementById(hiddenRow_id).className = 'hiddenRow';
}
}
</script>
{% endblock %}
{% block content %}
<div class="page-header">
<h1 class="text-primary" style="font-size:45px;line-height:75px">testfan测试报告</h1>
</div>
<div class="col-md-12">
<div class="col-md-4" style="Background-Color:#F5F5F5; height:300px">
<h3 style="line-height:25px">测试基本信息</h3>
<table class="table table-hover table-bordered" style="width:100%;height:11px">
<tbody>
<tr class="info">
<td class="text-center">开始时间</td>
<td id="start" class="text-center"></td>
</tr>
<tr class="info">
<td class="text-center">结束时间</td>
<td id="end" class="text-center"></td>
</tr>
<tr class="info">
<td class="text-center">测试用时</td>
<td id="spend" class="text-center"></td>
</tr>
<tr class="info">
<td class="text-center">总用例数</td>
<td id="total" class="text-center"></td>
</tr>
<tr class="info">
<td class="text-center">执行用例数</td>
<td id="run" class="text-center"></td>
</tr>
<tr class="info">
<td class="text-center">跳过用例数</td>
<td id="skip" class="text-center"></td>
</tr>
</tbody>
</table>
</div>
<div class="col-md-8">
<!-- 为ECharts准备一个具备大小(宽高)的Dom -->
<div id="pie" style="height:300px;"></div>
</div>
</div>
<div>
<div><span> </span></div>
<div class="col-md-12">
<div class="tabbable" id="tabs-957640">
<ul class="nav nav-tabs">
<li class="active">
<a href="#panel-0" data-toggle="tab" style="Background-Color: #428bca; color: #fff;">全 部 (<label
id="t-total"></label>)</a>
</li>
<li>
<a href="#panel-1" data-toggle="tab" style="Background-Color: #5cb85c; color: #fff;">成 功 (<label
id="t-success"></label>)</a>
</li>
<li>
<a href="#panel-2" data-toggle="tab" style="Background-Color: #d9534f; color: #fff;">失 败 (<label
id="t-fail"></label>)</a>
</li>
<li>
<a href="#panel-3" data-toggle="tab" style="Background-Color: #5bc0de; color: #fff;">未验证 (<label
id="t-skip"></label>)</a>
</li>
</ul>
</div>
<div class="tab-content">
<div class="tab-pane active" id="panel-0">
<table class="table table-hover table-bordered">
<tbody id="panel-data-0">
<tr class="all">
<td class="text-center" style="Background-Color:#dff0d8">用例编号</td>
<td class="text-center" style="Background-Color:#dff0d8">测试域名</td>
<td class="text-center" style="Background-Color:#dff0d8">接口方法</td>
<td class="text-center" style="Background-Color:#dff0d8">测试状态</td>
<td class="text-center" style="Background-Color:#dff0d8">测试结果</td>
</tr>
</tbody>
</table>
</div>
<div class="tab-pane" id="panel-1">
<table class="table table-hover table-bordered">
<tbody id="panel-data-1">
<tr class="all">
<td class="text-center" style="Background-Color:#dff0d8">用例编号</td>
<td class="text-center" style="Background-Color:#dff0d8">测试域名</td>
<td class="text-center" style="Background-Color:#dff0d8">接口方法</td>
<td class="text-center" style="Background-Color:#dff0d8">测试状态</td>
<td class="text-center" style="Background-Color:#dff0d8">测试结果</td>
</tr>
</tbody>
</table>
</div>
<div class="tab-pane" id="panel-2">
<table class="table table-hover table-bordered">
<tbody id="panel-data-2">
<tr class="all">
<td class="text-center" style="Background-Color:#dff0d8">用例编号</td>
<td class="text-center" style="Background-Color:#dff0d8">测试域名</td>
<td class="text-center" style="Background-Color:#dff0d8">接口方法</td>
<td class="text-center" style="Background-Color:#dff0d8">测试状态</td>
<td class="text-center" style="Background-Color:#dff0d8">测试结果</td>
</tr>
</tbody>
</table>
</div>
<div class="tab-pane" id="panel-3">
<table class="table table-hover table-bordered">
<tbody id="panel-data-3">
<tr class="all">
<td class="text-center" style="Background-Color:#dff0d8">用例编号</td>
<td class="text-center" style="Background-Color:#dff0d8">测试域名</td>
<td class="text-center" style="Background-Color:#dff0d8">接口方法</td>
<td class="text-center" style="Background-Color:#dff0d8">测试状态</td>
<td class="text-center" style="Background-Color:#dff0d8">测试结果</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
{% endblock %}
蓝图的视图
from flask import request
from flask import jsonify
from flask import Blueprint
from flask import render_template
from interface.logic import Logic
""" 接口测试蓝图 """
interface = Blueprint('interface', __name__,
static_folder='static', # interface蓝图的静态文件
template_folder='templates', # interface的模板
url_prefix='/interface') # interface的路由,host:port/interface/+...
@interface.route('create')
def create():
""" 创建接口测试页面的路由 """
return render_template("create.html")
@interface.route('/api/v1/debug', methods=['POST'])
def api_v1_debug():
""" debug接口处理视图 """
# get请求使用request.values.to_dict接收,post、put、delete使用request.get_json接收
data = request.get_json()
# 判断有没有传method参数
method = data.get('method', None)
if not method:
return jsonify({
'status': 400,
'message': 'method参数必传',
'data': data,
})
# 判断有没有传host参数
host = data.get('host', None)
if not host:
return jsonify({
'status': 400,
'message': 'host参数必传',
'data': data,
})
# 处理逻辑
try:
status, message, data = Logic().execute(data)
return jsonify({
'status': status,
'message': message,
'data': data,
})
except Exception as error:
return jsonify({
'status': 500,
'message': str(error),
'data': data
})
@interface.route('/api/v1/save', methods=['POST'])
def api_v1_save():
""" 保存接口处理视图 """
data = request.get_json()
# 定义错误的返回内容
fail = {
'status': 400,
'data': data,
}
# 校验method必传
method = data.get('method', None)
if not method:
fail.setdefault('message', 'method参数必传')
return jsonify(fail)
# 校验host必传
host = data.get('host', None)
if not host:
fail.setdefault('message', 'host参数必传')
return jsonify(fail)
# 执行保存逻辑,保存成功就返回id,否则就返回接收的内容
try:
ids = Logic().save(data)
return jsonify({
'status': 0,
'message': 'success',
'data': ids,
})
except Exception as error:
return jsonify({
'status': 500,
'message': str(error),
'data': data
})
@interface.route('report/<id>')
def report(id):
""" 访问时为report/runid """
return render_template("report.html")
@interface.route('/api/v1/trigger', methods=['POST'])
def api_v1_trigger():
""" 触发运行用例接口 """
data = request.values.to_dict() # 接收参数(这里前端传字典格式)
ids = data.get('id', None) # 拿前端传过来的id
if not ids: # 没有传id就返回400
return jsonify({
'status': 400,
'message': 'id必传',
'data': data,
})
# 执行触发运行
try:
result = Logic().trigger(data)
return jsonify({
'status': 0,
'message': 'success',
'data': result,
})
except Exception as error:
return jsonify({
'status': 500,
'message': str(error),
'data': data
})
@interface.route("/api/v1/report", methods=['POST'])
def api_v1_report():
""" 根据runid查测试据结果数据 """
data = request.get_json()
print(data)
id = data.get('id', None)
if not id:
return jsonify({
'status': 400,
'message': 'invalid parameter [id]',
'data': data,
})
try:
report = Logic().report(data)
return jsonify({
'status': 0,
'message': 'success',
'data': report,
})
except Exception as error:
return jsonify({
'status': 500,
'message': str(error),
'data': data
})
interface蓝图的处理逻辑
import time
import requests
from jsonpath import jsonpath
from common.mongo import Mongo
from common import get_case_id
from common import get_timestamp
""" 功能处理逻辑 """
class Logic(object):
JSONPATH_ASSERT_SUCCESS = 0 # jsonpath断言通过
HTTP_REQUEST_FAIL = 1 # 请求失败
JSONPATH_ASSERT_FAIL = 2 # 断言不通过
JSONPATH_EXECUTE_FAIL = 3 # jsonpath取值失败
RESPONSE_DATA_FORMAT_ERROR = 4 # 相应数据格式错误
def __init__(self):
self.db = Mongo()
def execute(self, data):
""" 用前端传过来的数据发送http请求,返回值为元组,分别是flag,message和接口请求后的json数据 """
# 拿对应数据
method = data.get("method")
host = data.get("host")
header = data.get('header', {})
payload = data.get('params', {})
# 发送http请求
if method == 'get':
response = requests.request(method, host, params=payload, headers=header)
else:
response = requests.request(method, host, data=payload, headers=header)
# 解析响应结果
try:
json = response.json()
except Exception:
flag = Logic.RESPONSE_DATA_FORMAT_ERROR
message = "响应数据非json"
return flag, message, {}
# 执行断言
# 初始化flag为JSONPATH_ASSERT_SUCCESS,message为测试成功
flag = Logic.JSONPATH_ASSERT_SUCCESS
message = "测试通过"
# 如果响应状态码不是200,则视请求接口失败
if response.status_code != 200:
flag = Logic.HTTP_REQUEST_FAIL
message = "请求接口失败!"
return flag, message, json
# 解析assert数据
items = data.get('assert', [])
# 把assert数据里的每一个rule(预期结果,jsonpath表达式)拿出来取数据
for item in items:
result = jsonpath(json, item['rule'])
# 如果返回的result没有值,则说明取值失败
if not result:
flag = Logic.JSONPATH_EXECUTE_FAIL
message = "jsonpath取值失败"
break
# 把所有预期结果分别转成str,再转为list
result = list(map(str, result))
# 判断两个list(预期结果和实际结果)是否相等['1', '2'] != ['1', '2']
if result != [item['expect']]:
flag = Logic.JSONPATH_ASSERT_FAIL
message = "测试断言不通过"
break
return flag, message, json # 根据断言状态返回状态码和信息
def save(self, data):
""" 保存用例的逻辑 """
print(data)
data.setdefault('_id', get_case_id()) # 把_id的值重新赋值为自定义的caseid
# 把数据保存到2019库里的interface表
ids = self.db.insert("2019", "interface", data) # 数据库层已经定义好了save完后返回自定义的caseid
return ids # 这里把拿到的id直接返回
def trigger(self, data):
""" 根据接收到的caseid触发运行case """
cases = []
# 前端传递过来的是一组用逗号分隔的ID,用ID去数据库里查找用例。
# 如果能查找到则放入cases里待后面去运行。
id_list = data.get('id').split(',') # 把所有的id分割为一个list
# 根据拿到的id去查caseid
for case_id in id_list:
results = self.db.search("2019", "interface", {'_id': case_id})
# 如果取出来的caseid有值,就加到cases里面
if not results:
continue
for result in results:
cases.append(result)
# 初始化测试结果数据,这个data是要存储到数据库的测试报告数据。
data = {
'_id': get_case_id(), # 定义run_id(运行id)
'time': { # 统计时间
'start': 0,
'end': 0,
'cost': 0,
},
'count': { # 统计用例执行相关的个数
'total': 0,
'run': 0,
'success': 0,
'fail': 0,
'skip': 0
},
'result': [] # 执行结果
}
start = time.time() # 开始运行时间
# 判断每一个测试用例是否通过。
for case in cases:
data['count']['total'] += 1 # 用例总数+1
data['count']['run'] += 1 # 执行数+1
status, message, _ = self.execute(case) # 执行并接收返回数据
if status == 0: # 判断返回状态 ,前面已经定义0位成功,1/2/3/4都是各种失败
data['count']['success'] += 1 # 成功数+1
else:
data['count']['fail'] += 1 # 失败数+1
# 更新case执行的状态和执行信息
case['status'] = status
case['message'] = message
data['result'].append(case) # 把更新状态后的case加到reslut里面
print("{0} {1} {2} {3}".format(data['count']['total'], data['count']['run'],
data['count']['success'], data['count']['fail']))
end = time.time() # 结束运行时间
# 通过start与end时间戳计算整个测试耗时
data['time']['start'] = get_timestamp(start) # 开始时间,字符串格式
data['time']['end'] = get_timestamp(end) # 结束时间,字符串格式
data['time']['cost'] = "共执行{0:0.3}秒".format(end - start) # 执行用的时间,保留3位小数
# 将测试报告数据写入数据库。
self.db.insert('2019', 'report', data)
return data['_id'] # 返回本次的run_id
def report(self, data):
""" 根据接收的runid查测试结果数据,用于生成html报告 """
run_id = data.get('id')
result = self.db.search("2019", "report", {'_id': run_id}) # 存到2019库的report表里面
return list(result)