测开之路六十一:接口测试平台之interface蓝图
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)
测开之路六十一:接口测试平台之interface蓝图的更多相关文章
- 测开之路六十:接口测试平台之common目录
实现接口测试平台使用jsonpath进行取值来断言,效果: 访问页面: 调试功能:http://www.kuaidi100.com/query 保存功能 触发执行功能 查看报告功能 目录结构 comm ...
- 测开之路六十二:接口测试平台之公共的js、html、平台入口
common.js //定义后台的host和端口var host = 'http://192.168.xxx.1:8000'; //'http://127.0.0.1:8000'; //用于发送htt ...
- 测开之路七十一:监控平台之js
监控平台的js //datetimepicker的初始化函数(主要是对选择时间的下拉框)function init_datetimepicker() { //初始化格式和规则 $('#start'). ...
- 测开之路六十六:UI测试平台之处理逻辑和蓝图添加到程序入口
from selenium import webdriverfrom common import get_case_idfrom common.mongo import Mongo class Log ...
- 测开之路六十五:UI测试平台之js
//添加网址的函数,生成一个输入网址的标签,并且把标签append到id为cases下function browser() { var html = '\ <div class="ro ...
- 测开之路六十四:UI测试平台之前端页面
{% extends "base.html" %} {% block script %} <!-- 引入js文件,需要在base.html留入口,不然渲染会出问题. --&g ...
- 测开之路六十三:UI测试平台之视图层
实现效果,在页面时配置 后台执行 蓝图结构 视图代码 from flask import jsonifyfrom flask import requestfrom flask import Bluep ...
- 测开之路九十一:css常用的选择器
一:全局选择器:* 二:标签选择器,如给所有p标签加个背景色 三:id选择器:# ,如给id为id_01的元素加一个框 四:类选择器:. 如设置一个类选择器为blue,当有标签引用blue的时候,背景 ...
- 测开之路八十一:参数定义之*args和**kwargs
# *,不定长参数,*args# 定义函数参数def avg(score, *scores): return (score + sum(scores)) / (len(scores) + 1) ...
随机推荐
- host文件无操作权限
把先用其它启动方式启动电脑,如winpe(网上有制作方法,很简单的),启动后找到FWPKCLNT.SYS所在文件夹, 一般在c/windows/system32/drivers,将drivers文件夹 ...
- MVC框架与MTC框架
3.WEB框架 MVC Model View Controller 数据库 模板文件 业务处理 MTV Model Template View 数据库 模板文件 业务处理 ############## ...
- 前端校招知识体系之css
本文将从以下四个方面展开介绍: 选择器 样式表继承 css3部分特性 BFC css选择器优先级策略 先附上个链接:css选择器参考手册 内联>id>class=属性选择器=伪类选择器&g ...
- V8引擎回收机制、 内存泄露
一.垃圾回收:将内存不在使用的数据进行清理,释放内存空间 v8将内存分为新生代空间和老生代的空间 新生代空间:用于存活较短的对象 :又分为二个空间:from空间和to空间 :Scav ...
- FCKeditor用在JSP中的几点注意事项
转自:https://blog.csdn.net/asinzy/article/details/3854127 本篇文章主要介绍了"FCKeditor用在JSP中的几点注意事项", ...
- Maya2017下载安装与激活
目录 1. 更多推荐 2. 下载地址 2.1. OneDrive 2.2. 百度云 3. 安装激活步骤 1. 更多推荐 其他Maya版本的下载与激活:https://www.cnblogs.com/c ...
- linux Sersync 上配置客户端
1.安装 Rsync 并配置相关权限 在 SERSYNC 上配置 RSYNC 客户端相关权限认证: [root@SERSYNC /]# yum install rsync -y [root@SERSY ...
- 10.Linux-CentOS系统重启之后Xshell无法SSH连接(云环境)
问题:云环境下CentOS系统断电或强制关机,再开机出现问题:Entering emergency mode. Exit the shell to continue. Generating " ...
- mysql的mod函数
取余是用函数mod(numer1,number2),其返回的值为其余数值 如:mod(id,2) = 1 返回id号是奇数的id
- flask之模板之继承
一:继承 基类模板base.html 中在进行挖坑 {% block 坑的名字%}{% endblock %} 子类模板test.html 中 通过 {% extends "base.ht ...