1. 程式人生 > >模擬測試環境實現隨機造數功能

模擬測試環境實現隨機造數功能

背景:需要實現如下功能

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模板

=================================================================================