不想當將軍的小兵,不是好的小兵;不想做開發的測試,不是好的測試;
不管你信不信,我是信了...
一直以來,內心總有些迷茫的時候,迷茫的是作為測試既然要學那么多編程,為什么不直接去干開發呢?
看了這句話,才發現自己鑽進了牛角尖,沒有站在更高的高度來思考測試這個崗位,而僅僅是作為一個測試員,或者說是抱着急功近利的心態在想問題,從而忽略了測試的本質。
測試的本質是盡可能的發現軟件的缺陷,更高級的應該是用更少的時間,更少的人員來找出更多的缺陷。那么不管更好的測試流程,更高效的測試方法,更好的測試工具,這些都應該是我們追求的東西。
流程,方法,工具,這三者中我認為更重要的應該是方法,最難提升的也是方法。
編碼啊工具之類的可以用到哪些提升哪些,
說到底,不管是開發中的編碼,還是測試中的編碼,都是很初級的工作,都不是這個職業鏈中的高端,高端應該是對設計對方法的研究與創新,甚至引發自己所處職業的一種潮流。
做好測試不是靠編程,而是靠的是嚴禁的作風,慎密的邏輯思維,適合的測試流程。從用戶角度,到系統角度,到黑產角度,既保證給普通用戶很好的用戶體驗,也保證系統運行平順流暢,也保證不能應為hacker的攻擊而功虧一簣
進入正題,最近在研究API接口中,異常測試用例的自動化問題,這邊考慮的自動化,是通過接口說明文檔,自動生成用例描述,用例的入參數據,用例的斷言數據,當然測試的級別不是最高的,可以設置為2左右
比如一個注冊接口,異常的測試用例,是不是需要判斷,每一個必傳入參是否傳入,那這邊就有2N條測試用例
1.請求傳入的必傳參數var1未傳,驗證返回var1....
2. 請求傳入的必傳參數var1傳入的為空字符串(String類型)/null(..), 驗證返回var1.....
異常測試用例還需要判斷入參的長度,是不是又有了
3. 請求傳入的參數var1超過最大長度限制,驗證返回var1
有些入參有要求,比如用list,異常測試用例又有了
4.請求傳入的參數Var1不是xx類型,驗證返回
入參最好還需要判斷是否將入參首位的空格去掉,異常測試用例又有了
5. 請求傳入的入參首尾含有空格,驗證存入DB中不含空格【要求代碼對入參的首尾空格做trim()操作】
對接口的異常測試用例,彌漫着滿滿的套路氣息,每次都進行編寫測試用例,創建測試用例數據和斷言等操作,入參多的時候,還是很費時間的,不利於提升工作效率。
更好的辦法是:編寫代碼,自動生成測試用例描述,組裝測試用例的數據,自動生成斷言等
以前,我們一直用Jmeter創建的腳本來自動生成上述內容,
Jmeter生成jmx腳本,腳本中指定了入參個數、類型,長度等,之后生成用例描述,用例數據和斷言
好處就是復用方便,更改下url直接測試
缺點就是,不利於動態生成用例,入參變化多了之后要重新創建新的腳本
還有一個缺點就是low,你若是說你用Jmeter做接口自動化測試的,大廠中廠都會嫌棄你low,因為人家是用Python做的,Java做的。
【low不low!!who cares?!!不是一樣能完成任務嗎,不一樣能持續化集成並發送測試報告嗎?你們一個組就100多號測試,也不就是完成這寫接口的自動化測試嗎,我們剛上手的實習生分分鍾都能講API測試用到飛】
感覺中國人,很喜歡用工具和方式來judge others,我們兄弟公司的人,大多是麻省理工學院的,api測試自動化還是用postman實現的呢,ui測試也只不過是protractor+jasmine等,人家不是low,夠用就好,有時候已經不提倡測試,直接leader 做code review
現在動態實現接口異常測試用例的生成,用一個簡單的例子
我們常見的接口說明文檔,是不是長這樣?
我頁面還沒開發完,大意就是講入參,和比天性,類型,最大長度,等信息填入表中。
CREATE TABLE [DBO].[QA_APIVAR]( [APIVAR_ID] [INT] IDENTITY(1,1) NOT NULL PRIMARY KEY, [API_ID] [INT] NOT NULL, [APIVAR_NAME] [VARCHAR](100) NULL, [APIVAR_INPUTFLAG] [BIT] NOT NULL DEFAULT 1, [APIVAR_INPUTDATATYPE] [VARCHAR](100) NULL, [APIVAR_INPUTDATATYPEID] INT NOT NULL, [APIVAR_INPUTLENGTH] INT NOT NULL, [APIVAR_INPUTSCOPE] [VARCHAR](100) NULL, [APIVAR_INPUTNOTE] [VARCHAR](200) NULL, [APIVAR_DELETED_FLAG] [BIT] NOT NULL DEFAULT 0, [APIVAR_CREATEDT] DATETIME NOT NULL, [APIVAR_UPDATEDT] DATETIME NOT NULL )
代碼單元測試部分,判斷必傳入參的未傳,生成測試用例描述,測試數據body【這邊以json格式為sample】,斷言暫未寫
package com.example.demo.api; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import java.util.List; import java.util.Random; @Controller public class ApiVar2Case { String ALLCHAR = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; @Autowired private ApiVarService apiVarService; @Autowired private ApiCaseService apiCaseService; @RequestMapping("/CheckMustVar") //根據必傳參數,依次生成"請求傳入的xx參數未傳,驗證返回" public void CheckMustVar() { List<ApiVarBean> list = apiVarService.CheckMustVar(1); System.out.println(list); System.out.println(list.size()); int max = 0; String body = null; for (int i = 0; i < list.size(); i++) { String var = list.get(i).getVal(); var = "請求中未傳入" + var + "驗證返回" + var + "~~更多斷言"; System.out.println(var); StringBuffer sb = new StringBuffer(); body = "{ \n"; for (int j = 0; j < list.size(); j++) { if (list.get(i).getVal() != list.get(j).getVal()) { Random random = new Random(); max = list.get(j).getInputLenght(); sb = new StringBuffer(""); for (int k = 0; k < max; k++) { sb.append(ALLCHAR.charAt(random.nextInt(ALLCHAR.length()))); } body = body + "\"" + list.get(j).getVal() + "\":\"" + sb + "\", \n"; } } body = body.substring(0, (body.length() - 3)) + " \n }"; System.out.println(body); ApiCaseBean apiCaseBean = new ApiCaseBean(); apiCaseBean.setApiCase_taskid(1); apiCaseBean.setApiCase_name(var); apiCaseBean.setApiCase_body(body); apiCaseBean.setApiCase_asseertion(null); apiCaseBean.setApiCase_priorityid(3); int count = apiCaseService.save(apiCaseBean); System.out.println(count); } } //根據必傳參數,依次生成"請求傳入的XX參數為空字符串" @RequestMapping("/CheckMustVarEmpty") public void CheckMustVarEmpty() { List<ApiVarBean> list = apiVarService.CheckMustVar(1); int max = 0; String body = null; for (int i = 0; i < list.size(); i++) { String var = list.get(i).getVal(); var = "請求中傳入" + var + "為空字符串驗證返回" + var + "~~更多斷言"; System.out.println(var); StringBuffer sb = new StringBuffer(); body = "{ \n"; for (int j = 0; j < list.size(); j++) { if (list.get(i).getVal() != list.get(j).getVal()) { Random random = new Random(); max = list.get(j).getInputLenght(); sb = new StringBuffer(""); for (int k = 0; k < max; k++) { sb.append(ALLCHAR.charAt(random.nextInt(ALLCHAR.length()))); } body = body + "\"" + list.get(j).getVal() + "\":\"" + sb + "\", \n"; } else { body = body + "\"" + list.get(j).getVal() + "\":\"" + "\", \n"; } } body = body.substring(0, (body.length() - 3)) + " \n }"; ApiCaseBean apiCaseBean = new ApiCaseBean(); apiCaseBean.setApiCase_taskid(1); apiCaseBean.setApiCase_name(var); apiCaseBean.setApiCase_body(body); apiCaseBean.setApiCase_asseertion(null); apiCaseBean.setApiCase_priorityid(3); int count = apiCaseService.save(apiCaseBean); System.out.println(count); } } //根據接口中參數,依次生成"請求傳入的XX參數為最大長度+1,即超過最大長度" @RequestMapping("/CheckVarOverLength") public void CheckVarOverLength() { List<ApiVarBean> list = apiVarService.CheckMustVar(1); int max = 0; String body = null; for (int i = 0; i < list.size(); i++) { String var = list.get(i).getVal(); int length = list.get(i).getInputLenght(); var = "請求中傳入" + var + "的長度為" + length + "實際傳入的長度為" + (length + 1) + "驗證返回" + var + "~~更多斷言"; System.out.println(var); StringBuffer sb = new StringBuffer(); body = "{ \n"; for (int j = 0; j < list.size(); j++) { Random random = new Random(); max = list.get(j).getInputLenght(); sb = new StringBuffer(""); if (list.get(i).getVal() != list.get(j).getVal()) { for (int k = 0; k < max; k++) { sb.append(ALLCHAR.charAt(random.nextInt(ALLCHAR.length()))); } } else { for (int k = 0; k <= max; k++) { sb.append(ALLCHAR.charAt(random.nextInt(ALLCHAR.length()))); } } body = body + "\"" + list.get(j).getVal() + "\":\"" + sb + "\", \n"; } body = body.substring(0, (body.length() - 3)) + " \n }"; ApiCaseBean apiCaseBean = new ApiCaseBean(); apiCaseBean.setApiCase_taskid(1); apiCaseBean.setApiCase_name(var); apiCaseBean.setApiCase_body(body); apiCaseBean.setApiCase_asseertion(null); apiCaseBean.setApiCase_priorityid(3); int count = apiCaseService.save(apiCaseBean); System.out.println(count); } } }
以下是生成的數據,我當然可以用個對象來接收,並存到數據庫中去
[ApiCaseBean{num=1, val='name', InputFlag=1, InputDataType='String', InputTypeID=1, InputLenght=5, InputNote='null'}, ApiCaseBean{num=2, val='ID', InputFlag=1, InputDataType='String', InputTypeID=1, InputLenght=5, InputNote='null'}, ApiCaseBean{num=3, val='mobile', InputFlag=1, InputDataType='String', InputTypeID=1, InputLenght=5, InputNote='null'}, ApiCaseBean{num=6, val='apple', InputFlag=1, InputDataType='String', InputTypeID=1, InputLenght=6, InputNote='null'}, ApiCaseBean{num=7, val='orange', InputFlag=1, InputDataType='String', InputTypeID=1, InputLenght=6, InputNote='null'}, ApiCaseBean{num=8, val='pear', InputFlag=1, InputDataType='String', InputTypeID=1, InputLenght=6, InputNote='null'}]
6
請求中未傳入name驗證返回name~~更多斷言
{
"ID":"zHUX3",
"mobile":"0J9jR",
"apple":"BTOfiV",
"orange":"ZUz1DB",
"pear":"8vHDVB"}
請求中未傳入ID驗證返回ID~~更多斷言
{
"name":"8gJfa",
"mobile":"5pKjY",
"apple":"7vZVSJ",
"orange":"45cTEN",
"pear":"v9FliS"}
請求中未傳入mobile驗證返回mobile~~更多斷言
{
"name":"Bi5Xm",
"ID":"OmYSR",
"apple":"IEYHCO",
"orange":"1zPaB6",
"pear":"Jw0d84"}
請求中未傳入apple驗證返回apple~~更多斷言
{
"name":"gesB1",
"ID":"fSCeE",
"mobile":"HmY6j",
"orange":"SKInay",
"pear":"kDeurf"}
請求中未傳入orange驗證返回orange~~更多斷言
{
"name":"KnSwW",
"ID":"9VKd2",
"mobile":"thAXp",
"apple":"apjji8",
"pear":"J3UkLR"}
請求中未傳入pear驗證返回pear~~更多斷言
{
"name":"OTKPo",
"ID":"5WgEh",
"mobile":"gfJZA",
"apple":"aXksSk",
"orange":"JCCGZp"}
生成測試用例的表
CREATE TABLE [DBO].[QA_APICASE]( [APICASE_ID] [INT] IDENTITY(1,1) NOT NULL PRIMARY KEY, [API_ID] [INT] NOT NULL, [APICASE_NAME] [VARCHAR](100) NULL, [APICASE_BODY] [NVARCHAR](2000) NULL, [APICASE_ASSERCTION] [VARCHAR](100) NULL, [APICASE_PRIORITYID] INT , [APICASE_PASSID] INT, [APICASE_DELETED_FLAG] [BIT] NOT NULL DEFAULT 0, [APICASE_MEMO] [NVARCHAR](2000) NULL, [APICASE_CREATEDT] DATETIME NOT NULL, [APICASE_UPDATEDT] DATETIME NOT NULL )
有了用例描述和數據后,不管用什么接口測試工具,還是自已用Java/Python寫的框架,導入數據即可
比如 https://www.cnblogs.com/qianjinyan/p/9951465.html