模擬測試環境實現隨機造數功能
背景:需要實現如下功能
1,提供自動測試介面功能,每天執行
2,隨機生成資料組成請求引數請求各個介面(某些引數必須要從資料庫讀取,隨機生成無法實現)
3,提供頁面,實現只輸入json字串,系統,請求服務ID,請求型別,便能夠請求各類介面
4,頁面請求的引數如果與測試用例的引數一致,返回測試用例的預測結果以及介面返回的結果,不一致,便單獨返回介面的請求結果
5,頁面能夠自動把json資料格式化以及把測試用例的結果與介面返回結果進行對比
==============================================================================
由於之前在伺服器上搭建了jenkins+tomcat+zookeeper+dubbo的環境,現已經部署了所有的線上執行專案,由此有如下思路
思路:
1,需要單獨部署一個獨立專案
2,獨立專案提供頁面輸入請求引數
3,需要提供定時任務
4,需要隨機生成資料
5,需要連線資料庫
基於此採取如下方案
方案:
1,選用springboot+mybatis+oracle+druid(如果需要再增加redis作為快取)
2,前端採用html+css+js+jquery+bootstrap3+ajax(頁面沒有實現自適應)
===============================================================================
前端頁面樣式
備註:此為一個頁面
============================================================================================
頁面程式碼:
<!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1"> <!-- 上述3個meta標籤*必須*放在最前面,任何其他內容都*必須*跟隨其後! --> <title>Jfpointscore-Test</title> <!-- Bootstrap --> <link href="css/bootstrap.css" rel="stylesheet"> <link href="css/style.css" rel="stylesheet"> <!-- jQuery (Bootstrap 的所有 JavaScript 外掛都依賴 jQuery,所以必須放在前邊) --> <script src="js/jquery-1.10.1.js"></script> <!-- 載入 Bootstrap 的所有 JavaScript 外掛。你也可以根據需要只加載單個外掛。 --> <script src="js/bootstrap.js"></script> <script src="js/index.js"></script> </head> <body> <!--容器 --> <div class="container"> <div class="page-header"> <h1>Compare Json<small></small></h1> </div> <div id="request_container" class="jumbotron"> <h4 id="tip_font" class="tip_font">請輸入Json資料</h4> <textarea id="input_content" class="request_content"></textarea> <div class="request_container_bottom"> <!--格式化按鈕 --> <div id="format_button" class="btn-group format_button" role="group" aria-label="..."> <button id="format_json" type="button" class="btn btn-default" onclick="click_format_json();">格式化</button> </div> <!--系統按鈕 --> <div class="blank_button btn"> System: </div> <div id="system_button" class="dropdown system_button"> <button class="btn btn-default dropdown-toggle" type="button" id="system_type" data-toggle="dropdown" aria-haspopup="true" aria-expanded="true" value=""> 請選擇請求應用 <span class="caret"></span> </button> <ul class="dropdown-menu" aria-labelledby="system_type"> <li><a href="javascript:void(0)" id="system_jfpointscore-service" onclick='get_system("jfpointscore-service");'>jfpointscore-service</a></li> <li role="separator" class="divider"></li> <li><a href="javascript:void(0)" id="system_jfpointscoreqry-service" onclick='get_system("jfpointscoreqry-service");'>jfpointscoreqry-service</a></li> <li role="separator" class="divider"></li> <li><a href="javascript:void(0)" id="system_jfpointscore-job" onclick='get_system("jfpointscore-job");'>jfpointscore-job</a></li> <li role="separator" class="divider"></li> <li><a href="javascript:void(0)" id="system_jfpointssettle-job" onclick='get_system("jfpointssettle-job");'>jfpointssettle-job</a></li> </ul> </div> <div class="blank_button btn"> RequestType: </div> <!--請求型別按鈕 --> <div id="request_button" class="dropdown request_button"> <button class="btn btn-default dropdown-toggle request_button_button" type="button" id="request_type" data-toggle="dropdown" aria-haspopup="true" aria-expanded="true" value=""> 請選擇請求型別 <span class="caret"></span> </button> <ul class="dropdown-menu" aria-labelledby="request_type"> <li><a href="javascript:void(0)" id="system_jfpointscore-service" onclick='get_request_type("biz");'>biz</a></li> <li role="separator" class="divider"></li> <li><a href="javascript:void(0)" id="system_jfpointscoreqry-service" onclick='get_request_type("dubbo");'>dubbo</a></li> <!-- <li><a href="#" onclick='get_system("none");'>reset</a></li> --> </ul> </div> <div class="blank_button btn"> ServiceId: </div> <!--serviceId --> <div class="form-group service_id" id="service_id"> <input id="serviceId" type="text" class="form-control" placeholder="ServiceId"> </div> <!--格式化按鈕 --> <div id="submit_button" class="btn-group submit_button" role="group" aria-label="..."> <button id="submit_request" type="button" class="btn btn-default" onclick="submit_request();">提交</button> </div> </div> </div> <div id="response_container" class="jumbotron response_container"> <div id="response_container_left" class="response_container_left"> <h4 id="tip_font_response" class="tip_font_response">測試用例引數</h4> <textarea id="out_content_left" class="response_content_left" readonly="readonly"></textarea> </div> <div id="response_container_middle" class="response_container_middle"> <!--格式化按鈕 --> <div id="response_format_button" class="btn-group response_format_button" role="group" aria-label="..."> <button id="response_format_json" type="button" class="btn btn-default response_format_json " onclick="format_result();">格式化</button> </div> </div> <div id="response_container_right" class="response_container_right"> <h4 id="tip_font_response" class="tip_font_response">系統返回引數</h4> <textarea id="out_content_right" class="response_content_right" readonly="readonly"></textarea> </div> <!--格式化按鈕 --> <div id="backup_format_button" class="btn-group backup_response_format_json" role="group" aria-label="..."> <button id="backup_response_format_json" type="button" class="btn btn-default" onclick="format_result();">格式化</button> </div> </div> </div> </body> </html>
=====================================================================
js程式碼:
//監聽textarea的內容 window.onload = function () { //獲取文字內容和長度函式 function txtCount(el) { var val = el.value; var eLen = val.length; return eLen; } var content = "請輸入Json資料"; var el = document.getElementById('input_content'); el.addEventListener('input',function () { var len = txtCount(this); // 呼叫函式 if(len == 0){ document.getElementById('tip_font').innerHTML = content; $("#tip_font").css("color","black"); } }); el.addEventListener('propertychange',function () {//相容IE var len = txtCount(this); // 呼叫函式 if(len == 0){ document.getElementById('tip_font').innerHTML = content; $("#tip_font").css("color","black"); } }); // $("#out_content_left").text("2222222"); // $("#out_content_right").text("11111111"); } /*格式化json資料*/ function formatJson(){ var flag = false; var text = $("#input_content").val(); //獲取json格式內容 var result = text; if(is_json(text)){ result = JSON.stringify(JSON.parse(text), null, 4);//將字串轉換成json物件 $("#tip_font").text("Json資料格式正確"); $("#tip_font").css("color","green"); flag = true; }else{ $("#tip_font").text("Json資料格式錯誤"); $("#tip_font").css("color","red"); } $("#input_content").val(result); return flag; } /*格式化json內容*/ function click_format_json(){ formatJson(); } /*判斷是否是json格式*/ function is_json(str) { var flag = false; if (typeof str == 'string') { try { var obj = JSON.parse(str); if(typeof obj == 'object' && obj ){ flag = true; }else{ flag = false; } } catch(e) { console.log('error:'+str+'!!!'+e); flag = false; } }else{ console.log('It is not a string!'); flag = false; } return flag; } /**獲取選擇的系統*/ function get_system(systemName){ console.log("傳入的系統為"+systemName); //var text = $("#system_"+systemName).html(); var text = systemName; console.log(text); $("#system_type").val(systemName);//button裡的值 $("#system_type").text(systemName); } /**獲取選擇的請求型別*/ function get_request_type(requestType){ console.log("傳入的請求型別為"+requestType); //var text = $("#system_"+systemName).html(); var text = requestType; console.log(text); $("#request_type").val(requestType); $("#request_type").text(requestType+""); } /**提交按鈕*/ function submit_request(){ var flag = false; var json = $("#input_content").val(); var system = $("#system_type").text();//button顯示的內容 var systemValue = $("#system_type").val();//button裡的值 var requestType = $("#request_type").text();//button顯示的內容 var requestTypeValue = $("#request_type").val();//button裡的值 var serviceId = $("#serviceId").val(); console.log(json); console.log(systemValue); console.log(requestTypeValue); console.log(serviceId); if(json.length == 0 || systemValue.length == 0 || requestTypeValue.length == 0 || serviceId.length == 0){ $("#tip_font").css("color","red"); if(json.length == 0){ $("#tip_font").text("json資料不可以為空!"); return; }else{ if(is_json()){ $("#tip_font").text(""); }else{ $("#tip_font").text("Json資料格式錯誤"); $("#tip_font").css("color","red"); } } if(systemValue.length == 0){ $("#tip_font").text("請求應用不可以為空!"); return; }else{ $("#tip_font").text(""); } if(requestTypeValue.length == 0){ $("#tip_font").text("請求型別不可以為空!"); return; }else{ $("#tip_font").text(""); } if(serviceId.length == 0){ $("#tip_font").text("serviceId不可以為空!"); return; }else{ $("#tip_font").text(""); } } if(json.length != 0 && systemValue.length != 0 && requestTypeValue.length != 0 && serviceId.length != 0){ flag = true; } if(flag){ if(formatJson()){ $("#tip_font").css("color","black"); timer(5); //請求後臺 request_admin(); } } } /*按鈕禁用5秒*/ function timer(time) { var btn = $("#submit_request"); btn.attr("disabled", true); //按鈕禁止點選 btn.text(time <= 0 ? "時間引數不正確" : ("" + (time) + "秒後可再次請求")); var hander = setInterval(function() { if (time <= 0) { clearInterval(hander); //清除倒計時 btn.text("提交"); btn.attr("disabled", false); return false; }else { btn.text("" + (time--) + "秒後可再次請求"); } }, 1000); } /*請求後臺*/ //後端使用@RequestBody接收請求使用此類 function request_admin(){ var url = "/jfpointscore-test/action"; $.ajax({ type: "post", url: url, data:JSON.stringify(get_json_data()), cache: false, async : true, dataType: "json", contentType: "application/json", success: function (data ,textStatus, jqXHR) { if("success"==data.status){ console.log("合法!"); console.log("===============測試用例結果如下=================="); console.log(JSON.stringify(data.resultTest)); console.log("===============請求引數結果如下=================="); console.log(JSON.stringify(data.result)); display_result_to_test(data.resultTest); display_result_to_result(data.result); return true; }else{ console.log("不合法!錯誤資訊如下:"+data.errorMsg); return false; } }, error:function (XMLHttpRequest, textStatus, errorThrown) { console.log("請求失敗!"); } }); } /*請求後臺*/ //後端如果使用HttpServletRequest接收請求,使用req.getParameter("system")獲取引數,就用此類寫法 function request_admin_http(){ var url = "/jfpointscore-test/action"; var json = $("#input_content").val(); var system = $("#system_type").text();//button顯示的內容 var systemValue = $("#system_type").val();//button裡的值 var requestType = $("#request_type").text();//button顯示的內容 var requestTypeValue = $("#request_type").val();//button裡的值 var serviceId = $("#serviceId").val(); $.ajax({ type: "post", url: url, data: {"system":systemValue,"requestType":requestTypeValue,"serviceId":serviceId,"json":json}, cache: false, async : true, dataType: "json", success: function (data ,textStatus, jqXHR) { if("true"==data.flag){ console.log("合法!"); return true; }else{ console.log("不合法!錯誤資訊如下:"+data.errorMsg); return false; } }, error:function (XMLHttpRequest, textStatus, errorThrown) { console.log("請求失敗!"); } }); } /*組裝json資料*/ function get_json_data() { var json = $("#input_content").val(); var system = $("#system_type").text();//button顯示的內容 var systemValue = $("#system_type").val();//button裡的值 var requestType = $("#request_type").text();//button顯示的內容 var requestTypeValue = $("#request_type").val();//button裡的值 var serviceId = $("#serviceId").val(); var jsonResult = { "system": systemValue, "requestType": requestTypeValue, "serviceId": serviceId, "json": json } return jsonResult; } //展示測試用例結果 function display_result_to_test(data){ var result = null; if(data == null || data == ""){ result = "暫無測試用例資料!" ; }else{ result = JSON.stringify(data); } $("#out_content_left").text(result); } //展示請求資料真實返回結果 function display_result_to_result(data){ var result = null; if(data == null || data == ""){ result = "返回資料異常!" ; }else{ result = JSON.stringify(data); } $("#out_content_right").text(result); } //返回結果格式化 function format_result(){ var test_result = $("#out_content_left").text(); var result = $("#out_content_right").text(); if(test_result != null && test_result != "" && test_result != "暫無測試用例資料!"){ test_result = JSON.stringify(JSON.parse(test_result), null, 4);//將字串轉換成json物件 } if(result != null && result != "" && result != "返回資料異常!"){ result = JSON.stringify(JSON.parse(result), null, 4);//將字串轉換成json物件 } $("#out_content_left").text(test_result); $("#out_content_right").text(result); }
============================================================
css程式碼
/* 容器 */ .container{ height:1200px; color:black; /* outline:1px solid black; */ width:100%; } .jumbotron{ height:40%; } /* 請求json內容框 */ .request_content{ width:100%; height:80%; color:blue; } .request_container_bottom{ width:100%; margin:0 auto; } .tip_font{ color:black; } /* 格式化按鈕 */ .format_button{ float:left; } /* 系統下拉按鈕 */ .system_button{ float:left; margin-left:-10px; } /* 請求型別下拉按鈕 */ .request_button{ float:left; margin-left:-10px; } /*提示 */ .blank_button{ margin-left:20px; float:left; text-align:center; line-height:20px; disabled:disabled; } /* ServiceId */ .service_id{ float:left; margin-left:-10px; width:30%; } /*提交按鈕 */ .submit_button{ float:left; margin-left:20px; } /************************************/ /*結果返回容器*/ .response_container{ height:50%; } .response_container_left{ width:45%; height:90%; /* outline:1px solid black; */ float:left; } .response_container_right{ width:45%; height:90%; /* outline:1px solid black; */ float:left; } .response_container_middle{ float:left; width:10%; height:100%; } .response_content_left{ width:100%; height:100%; color:blue; } .response_content_right{ width:100%; height:100%; color:blue; } /*格式化按鈕*/ .response_format_button{ margin:200% 20%; } /*備用按鈕*/ .backup_response_format_json{ float:right; display:none; position:absolute; right:5%; } textarea:focus{ outline: none; } @media only screen and (max-width: 1150px){ .response_container_middle{display:none} .backup_response_format_json{display:block;} }
=======================================================================
JAVA程式碼部分:
由於程式碼無法從公司帶出,所以只提供思路
1,springboot的整合請自行百度
2,關於測試應用介面的定時任務,本人採取的做法是100介面就有100個定時任務
3,隨機生成資料問題
100個介面對應100個不同的實體類,那麼怎麼做呢?提供一個通用的方法,使用Random類隨機生成各種型別的資料(能解決大部分的介面,特殊介面特殊對待)。
jdk有方法能夠遍歷每一個class裡的屬性,方法,屬性的型別等,寫一個方法去遍歷傳遞進來的類,進行匹配,一般的引數都逃不過12種資料型別
byte,short,int,long,float,double,boolean,char,string,Integer,Date,Bigdecimal這12種。
4,關於每一個介面的引數欄位有必傳和非必傳的問題
本人提供3種做法
1,在resources目錄下生成json檔案,裡面存放json資料,每一個介面對應一個json檔案,json檔案裡的key是類的屬性,value是Y和N,Y代表必傳,N代表非必傳
每個定時任務讀取對應的json檔案,然後用隨機的Random類生成boolean做為if條件
2,自定義註解,在每個類的屬性上都定義這個註解,裡面的值就是Y和N
3,使用StringTemplate模板
=================================================================================