試實(shí)戰(zhàn):從安裝配置到壓測(cè)的完整指南)
早幾年剛開(kāi)始做接口測(cè)試那會(huì)兒團(tuán)隊(duì)里用的基本都是Postman。調(diào)試單個(gè)接口確實(shí)方便但接口一多起來(lái)就麻煩了今天改了個(gè)參數(shù)明天又要重新點(diǎn)一遍回歸一次得手動(dòng)跑幾十個(gè)請(qǐng)求點(diǎn)得手腕疼。后來(lái)被推薦用Jmeter做HTTP接口測(cè)試一開(kāi)始以為只是換了個(gè)錄制工具真正用起來(lái)才發(fā)現(xiàn)這東西從單接口驗(yàn)證、批量回歸到后面的壓力測(cè)試一條鏈路全包了而且還免費(fèi)開(kāi)源社區(qū)資料也多。這份總結(jié)把我這幾年用Jmeter做http接口測(cè)試的經(jīng)驗(yàn)全部整理出來(lái)包括安裝環(huán)境、組件邏輯、參數(shù)化、斷言寫(xiě)法、壓測(cè)擴(kuò)展還有一堆實(shí)際踩過(guò)的坑。適合剛?cè)胄邢胱鼋涌跍y(cè)試的新人也適合正在從Postman往Jmeter遷移的同學(xué)想順手把性能測(cè)試一起做了的也可以參考。1. 動(dòng)手準(zhǔn)備JDK與Jmeter安裝以及那些安裝期就會(huì)勸退你的坑1.1 JDK版本選擇與JAVA_HOMEJmeter本質(zhì)上是Java程序第一步必須是裝JDK。版本這塊很多人會(huì)忽略Jmeter 5.x在JDK 8下能跑但我建議直接用JDK 8或JDK 11別貪新上JDK 17以上。原因很簡(jiǎn)單Jmeter本身是純Java應(yīng)用高版本JDK反而容易遇到模塊化限制和某些加密組件的兼容問(wèn)題尤其在做HTTPS協(xié)議接口測(cè)試的時(shí)候JDK版本過(guò)高偶爾會(huì)報(bào)TLS握手異常。JDK下載后配置環(huán)境變量Windows下右鍵“此電腦”-“屬性”-“高級(jí)系統(tǒng)設(shè)置”-“環(huán)境變量”新建JAVA_HOME指向JDK安裝目錄再在Path里加一條%JAVA_HOME%\bin。配好之后打開(kāi)命令行敲java -version能正常輸出版本號(hào)就說(shuō)明環(huán)境OK。這個(gè)步驟別跳過(guò)很多Jmeter啟動(dòng)閃退的問(wèn)題最后查下來(lái)都是JDK沒(méi)配好或者裝了多個(gè)JDK導(dǎo)致版本沖突。1.2 Jmeter下載與啟動(dòng)Jmeter官網(wǎng)下載頁(yè)面提供兩種壓縮包apache-jmeter-xxx.zip和apache-jmeter-xxx.tgzWindows選zipLinux/macOS選tgz。下載后解壓到一個(gè)沒(méi)有中文和空格的路徑比如D:\tools\apache-jmeter-5.6.3這一點(diǎn)很關(guān)鍵路徑帶中文會(huì)導(dǎo)致后續(xù)腳本保存、CSV讀取的時(shí)候出現(xiàn)莫名其妙的編碼問(wèn)題。啟動(dòng)方式有兩種圖形界面啟動(dòng)進(jìn)bin目錄雙擊jmeter.batWindows或jmeterLinux/macOS命令行啟動(dòng)則用jmeter -n -t 腳本.jmx -l 結(jié)果.jtl。剛開(kāi)始學(xué)習(xí)階段主要用圖形界面因?yàn)槟苤庇^看到測(cè)試計(jì)劃的樹(shù)形結(jié)構(gòu)調(diào)試也方便。如果雙擊后彈出一個(gè)黑窗口然后又沒(méi)反應(yīng)了多半是JDK環(huán)境變量的問(wèn)題先去排查JAVA_HOME。1.3 界面錯(cuò)亂、環(huán)境變量與命令行啟動(dòng)很多人第一次打開(kāi)Jmeter會(huì)碰到界面錯(cuò)亂、按鈕重疊、窗口撐不開(kāi)的問(wèn)題這在高分辨率或系統(tǒng)縮放比例不是100%的電腦上特別常見(jiàn)。原因是Jmeter的Swing界面在高DPI縮放下沒(méi)有正確適配默認(rèn)的字體渲染會(huì)變得擁擠。解決方法有兩個(gè)一是右鍵jmeter.bat選擇屬性在兼容性里勾選“替代高DPI縮放行為”并設(shè)置為“系統(tǒng)”二是修改bin目錄下的jmeter.bat在啟動(dòng)參數(shù)里加上-Dsun.java2d.dpiawarefalse。實(shí)測(cè)下來(lái)第二種方案更穩(wěn)定一勞永逸。環(huán)境變量Jmeter本身不是必須配的不配置也能通過(guò)雙擊啟動(dòng)但建議還是配一下JMETER_HOME并把%JMETER_HOME%\bin加進(jìn)Path因?yàn)楹竺孀雒钚袎簻y(cè)、集成CI流水線的時(shí)候都需要在任意目錄下直接執(zhí)行jmeter命令。配置完成后再運(yùn)行jmeter -v能輸出版本信息就說(shuō)明安裝工作徹底結(jié)束了。2. HTTP接口測(cè)試的基本功先把請(qǐng)求拆明白再動(dòng)手建腳本2.1 HTTP請(qǐng)求的四要素URL、Method、Header、Body很多新手拿到一個(gè)接口文檔就直接往Jmeter里填填完跑不通就一臉懵。其實(shí)做HTTP接口測(cè)試本質(zhì)就是模擬客戶端向服務(wù)端發(fā)起一次HTTP請(qǐng)求只要把四個(gè)要素搞明白剩下的都是工具操作問(wèn)題。第一是URL也就是接口地址包含協(xié)議、域名、端口和路徑第二是請(qǐng)求方法GET、POST、PUT、DELETE這些第三是請(qǐng)求頭Header里面放Content-Type、Authorization、Cookie、User-Agent等附加信息第四是請(qǐng)求體BodyPOST、PUT請(qǐng)求一般都會(huì)帶參數(shù)格式可能是JSON、表單application/x-www-form-urlencoded或者multipart文件流。用一個(gè)實(shí)際項(xiàng)目里的登錄接口舉例POST https://api.example.com/loginHeader里需要Content-Type: application/jsonBody是{username:admin,password:123456}。把這四個(gè)要素在Jmeter的HTTP請(qǐng)求取樣器里對(duì)應(yīng)填好請(qǐng)求就能發(fā)出去了。接口測(cè)試之所以難往往不是工具操作難而是你連接口文檔都讀不懂不知道這個(gè)接口要什么參數(shù)、返回什么結(jié)構(gòu)。2.2 瀏覽器F12才是你最該用的抓包工具接口文檔不完整甚至壓根沒(méi)有這在現(xiàn)實(shí)項(xiàng)目里太常見(jiàn)了。這時(shí)候最快的獲取接口信息方式就是打開(kāi)瀏覽器按F12進(jìn)入開(kāi)發(fā)者工具。以Chrome為例切到Network標(biāo)簽頁(yè)勾選Preserve log保留日志然后在頁(yè)面上操作你要測(cè)的功能比如登錄、查詢、提交表單。瀏覽器會(huì)把每一次HTTP請(qǐng)求都記錄下來(lái)點(diǎn)擊某個(gè)請(qǐng)求就能看到完整的URL、請(qǐng)求方法、請(qǐng)求頭、請(qǐng)求體和響應(yīng)內(nèi)容。在請(qǐng)求上右鍵選擇Copy - Copy as cURL還能把請(qǐng)求轉(zhuǎn)成curl命令信息量極其完整。拿到這些信息后再對(duì)照著往Jmeter里填基本就不會(huì)漏字段。這里分享一個(gè)實(shí)際經(jīng)驗(yàn)很多項(xiàng)目的前端請(qǐng)求頭里帶了timestamp、sign等簽名參數(shù)這種接口直接照抄瀏覽器抓到的參數(shù)值是能通的但如果你要做參數(shù)化回歸測(cè)試就需要先和后端確認(rèn)簽名規(guī)則否則換一組參數(shù)就會(huì)全部報(bào)簽名錯(cuò)誤。這部分會(huì)在后面參數(shù)化章節(jié)詳細(xì)展開(kāi)。2.3 HTTP請(qǐng)求默認(rèn)值和管理器組件的作用Jmeter左側(cè)的測(cè)試計(jì)劃樹(shù)里你會(huì)在Thread Group下面看到一堆以“配置元件”命名的東西比如HTTP請(qǐng)求默認(rèn)值、HTTP信息頭管理器、HTTP Cookie管理器。很多人不懂這些組件的意義覺(jué)得是多余的其實(shí)它們的核心作用是“復(fù)用”。HTTP請(qǐng)求默認(rèn)值是針對(duì)同一線程組下多個(gè)HTTP請(qǐng)求的公共配置。比如你測(cè)的接口服務(wù)器域名都是api.example.com端口都是443協(xié)議都是https那就不用在每個(gè)HTTP請(qǐng)求取樣器里重復(fù)填只在這個(gè)配置元件里填一次取樣器里留空即可。這么做最大的好處是哪天環(huán)境從測(cè)試環(huán)境切到預(yù)發(fā)環(huán)境你只需要改HTTP請(qǐng)求默認(rèn)值里的域名整個(gè)腳本全部生效不用一個(gè)個(gè)去改。HTTP信息頭管理器則是用來(lái)統(tǒng)一管理公共請(qǐng)求頭的比如所有請(qǐng)求都要帶上Content-Type: application/json、Authorization: Bearer xxx就在這里集中配置。還有一個(gè)容易被忽視的HTTP Cookie管理器它用來(lái)處理服務(wù)器下發(fā)的Cookie尤其是在有登錄態(tài)的接口鏈路中你登錄后拿到Set-Cookie后續(xù)請(qǐng)求需要帶著這個(gè)Cookie訪問(wèn)Cookie管理器會(huì)自動(dòng)幫你在同一個(gè)線程內(nèi)維護(hù)不需要手動(dòng)傳值。3. 完整實(shí)操?gòu)目债?huà)布到跑通第一個(gè)接口測(cè)試腳本3.1 新建測(cè)試計(jì)劃與線程組打開(kāi)Jmeter后默認(rèn)會(huì)有一個(gè)空白的“Test Plan”。在Test Plan上右鍵添加 - 線程 - 線程組這樣就創(chuàng)建了第一個(gè)線程組。線程組是Jmeter里模擬用戶并發(fā)的基本單位這里需要理解三個(gè)核心參數(shù)線程數(shù)模擬多少個(gè)用戶同時(shí)發(fā)起請(qǐng)求。做接口測(cè)試階段線程數(shù)設(shè)1就行了因?yàn)槲覀冎饕?yàn)證接口功能正確性不需要并發(fā)。Ramp-Up時(shí)間秒在多長(zhǎng)時(shí)間內(nèi)把線程全部啟動(dòng)起來(lái)。假如線程數(shù)是10Ramp-Up填10就是1秒啟動(dòng)1個(gè)線程做功能驗(yàn)證時(shí)填0或1都行。循環(huán)次數(shù)每個(gè)線程執(zhí)行多少次請(qǐng)求。接口回歸時(shí)如果想跑100條測(cè)試數(shù)據(jù)線程數(shù)設(shè)1循環(huán)次數(shù)設(shè)100配合參數(shù)化就可以挨個(gè)執(zhí)行。線程組的調(diào)度器Scheduler配置里還有個(gè)Duration字段這個(gè)是壓測(cè)階段用來(lái)控制總執(zhí)行時(shí)長(zhǎng)的。功能測(cè)試階段用不上先不做深入說(shuō)明但你要知道有這個(gè)東西。3.2 HTTP請(qǐng)求取樣器的全部關(guān)鍵配置在已創(chuàng)建的線程組上右鍵添加 - 取樣器 - HTTP請(qǐng)求這會(huì)創(chuàng)建一個(gè)取樣器它是真正發(fā)起請(qǐng)求的組件。字段不多但要理解每一欄的含義。首先設(shè)置協(xié)議填http或https注意這里不要帶冒號(hào)和斜線然后填寫(xiě)服務(wù)器名稱或IP比如api.example.com同樣不要帶協(xié)議頭端口按接口文檔填默認(rèn)HTTP是80、HTTPS是443但很多項(xiàng)目?jī)?nèi)部接口用的是8080、8081這類自定義端口別填錯(cuò)。方法下拉選擇GET、POST等。路徑填接口的URI比如/api/login斜杠開(kāi)頭。如果URL帶查詢參數(shù)比如/api/getUser?id1nametest可以有兩種填法直接在路徑里帶上完整參數(shù)串比較直觀但不利于參數(shù)化或者把參數(shù)拆分到下方的Parameters列表里用變量占位這是推薦做法。POST請(qǐng)求的Body區(qū)域先看接口要求的Content-Type再?zèng)Q定怎么填。如果是JSON格式在HTTP信息頭管理器里設(shè)置好Content-Type: application/json然后在Body Data區(qū)域直接填JSON字符串如果是表單格式切到Parameters標(biāo)簽頁(yè)逐行填寫(xiě)參數(shù)名和值。這里有個(gè)常見(jiàn)錯(cuò)誤Header里設(shè)了JSONBody里卻拿表單格式填服務(wù)端解析不了就報(bào)參數(shù)缺失。3.3 查看結(jié)果樹(shù)與調(diào)試手段請(qǐng)求配置好了怎么知道到底通沒(méi)通在線程組上右鍵添加 - 監(jiān)聽(tīng)器 - 查看結(jié)果樹(shù)。運(yùn)行腳本后結(jié)果樹(shù)里會(huì)展示每一個(gè)請(qǐng)求的取樣器名稱、運(yùn)行時(shí)間、響應(yīng)狀態(tài)和響應(yīng)體內(nèi)容。我調(diào)試接口腳本時(shí)的標(biāo)準(zhǔn)流程是先看響應(yīng)狀態(tài)是不是200再看響應(yīng)體里的業(yè)務(wù)字段比如code是不是0、message是不是success最后結(jié)合接口文檔核對(duì)返回的關(guān)鍵數(shù)據(jù)比如用戶列表接口返回的數(shù)組長(zhǎng)度是不是等于你傳入的查詢條數(shù)。只看HTTP狀態(tài)碼是不夠的HTTP 200只代表網(wǎng)絡(luò)傳輸層成功不代表業(yè)務(wù)邏輯對(duì)。這里有個(gè)非常實(shí)用的調(diào)試技巧配合“調(diào)試取樣器”Debug Sampler使用。在線程組下添加一個(gè)調(diào)試取樣器它會(huì)把Jmeter當(dāng)前作用域內(nèi)的所有變量值輸出到結(jié)果樹(shù)里。這樣你就能確認(rèn)參數(shù)化文件讀進(jìn)來(lái)的值對(duì)不對(duì)、上一接口提取的token有沒(méi)有成功存進(jìn)變量。一句話總結(jié)先跑一次看結(jié)果樹(shù)再放個(gè)Debug Sampler看變量接口測(cè)試腳本的調(diào)試工作就完成80%了。3.4 讓腳本學(xué)會(huì)自己判斷對(duì)錯(cuò)如果不加斷言Jmeter默認(rèn)只要響應(yīng)碼在200-399之間就算請(qǐng)求成功這在做接口功能驗(yàn)證的時(shí)候是遠(yuǎn)遠(yuǎn)不夠的。比如你傳了一個(gè)錯(cuò)誤的密碼服務(wù)端返回400這說(shuō)明請(qǐng)求本身沒(méi)毛病是認(rèn)證失敗這算測(cè)試用例執(zhí)行成功但業(yè)務(wù)層面驗(yàn)證的是“錯(cuò)誤密碼應(yīng)該被拒絕”。所以我們必須給請(qǐng)求添加斷言。在HTTP請(qǐng)求取樣器上右鍵添加 - 斷言 - 響應(yīng)斷言。最常用的配置是把“要測(cè)試的響應(yīng)字段”選為“響應(yīng)文本”然后把期望包含的字符串填進(jìn)去。比如正確密碼登錄后響應(yīng)里有code:0斷言就填code:0匹配規(guī)則選“包括”這樣只要響應(yīng)文本里出現(xiàn)這個(gè)片段就算通過(guò)。這一步做完腳本才算真正具備判斷能力執(zhí)行完直接看斷言通過(guò)率就知道功能對(duì)不對(duì)。4. 參數(shù)化與數(shù)據(jù)驅(qū)動(dòng)一份CSV跑完幾百條用例4.1 三種參數(shù)化方式對(duì)比接口測(cè)試做一段時(shí)間后你會(huì)遇到一個(gè)典型問(wèn)題一條用例跑通了但接口的參數(shù)有幾十種組合需要覆蓋驗(yàn)證比如不同角色、不同權(quán)限、不同分頁(yè)條件。總不能復(fù)制幾十個(gè)HTTP請(qǐng)求吧這時(shí)候就需要參數(shù)化。Jmeter里常見(jiàn)的參數(shù)化方式有三種。第一種是“用戶定義的變量”在測(cè)試計(jì)劃級(jí)或線程組級(jí)添加適合存全局固定的配置值比如服務(wù)器地址、公共賬號(hào)、固定token。第二種是“CSV數(shù)據(jù)文件設(shè)置”從外部文件讀取每一行的數(shù)據(jù)作為變量值適合大批量數(shù)據(jù)驅(qū)動(dòng)比如100條測(cè)試數(shù)據(jù)的逐條執(zhí)行。第三種是“函數(shù)助手”里的隨機(jī)函數(shù)比如${__Random(1,100)}適合生成隨機(jī)參數(shù)驗(yàn)證接口健壯性。三種方式不是互斥的實(shí)際項(xiàng)目中通常是組合使用用戶定義的變量存全局配置CSV文件存批量測(cè)試數(shù)據(jù)隨機(jī)函數(shù)用于個(gè)別需要?jiǎng)討B(tài)生成的字段。4.2 CSV數(shù)據(jù)文件設(shè)置的完整細(xì)節(jié)在線程組上右鍵添加 - 配置元件 - CSV數(shù)據(jù)文件設(shè)置。這個(gè)組件幾個(gè)關(guān)鍵字段需要重點(diǎn)理解。Filename填CSV文件的絕對(duì)路徑注意Windows下路徑分隔符用斜杠D:/data/test.csv別用反斜杠否則某些環(huán)境會(huì)報(bào)找不到文件。文件編碼一般選UTF-8如果項(xiàng)目是老系統(tǒng)用GBK就選GBK不然讀取出來(lái)是亂碼。變量名這一欄是核心用逗號(hào)分隔填寫(xiě)每一列對(duì)應(yīng)的變量名比如第一列用戶名第二列密碼就填username,password后續(xù)通過(guò)${username}和${password}引用?!坝龅轿募Y(jié)束符再次循環(huán)”這個(gè)選項(xiàng)在功能測(cè)試?yán)镂医ㄗh設(shè)為T(mén)rue這樣數(shù)據(jù)用完了會(huì)從頭再讀適合長(zhǎng)時(shí)間跑穩(wěn)定性驗(yàn)證。但如果你想精確控制每個(gè)用例只跑一次就設(shè)為False?!熬€程共享模式”保持默認(rèn)的“所有線程”即可只有做壓測(cè)時(shí)才需要針對(duì)多線程考慮數(shù)據(jù)分配。一個(gè)重要的點(diǎn)CSV文件里第一行千萬(wàn)別放表頭Jmeter會(huì)把表頭當(dāng)真實(shí)數(shù)據(jù)執(zhí)行除非你把表頭行注釋掉或者在文件路徑下面配置跳過(guò)首行。4.3 一個(gè)數(shù)據(jù)驅(qū)動(dòng)的完整示例拿一個(gè)用戶查詢接口舉例。業(yè)務(wù)是傳入用戶名返回該用戶的詳細(xì)信息需要驗(yàn)證的用戶名有50個(gè)。我實(shí)際項(xiàng)目里的做法是第一步準(zhǔn)備一個(gè)CSV文件三列分別為用戶名、預(yù)期狀態(tài)、預(yù)期結(jié)果。這里預(yù)期狀態(tài)和預(yù)期結(jié)果不是必須的但加上之后可以把斷言也數(shù)據(jù)化比如預(yù)期code為0就斷言成功預(yù)期code為1001就斷言用戶不存在。第二步在線程組下新建HTTP請(qǐng)求路徑填/api/user/query方法GET參數(shù)里username填${username}。然后添加響應(yīng)斷言匹配規(guī)則選“包括”斷言文本填code:${status}這樣每讀一行數(shù)據(jù)斷言校驗(yàn)的期望值也不同。第三步線程組循環(huán)次數(shù)設(shè)為CSV行數(shù)或者勾選“永遠(yuǎn)”配合結(jié)束后停止。運(yùn)行后查看結(jié)果樹(shù)就可以看到50條用例逐條執(zhí)行每一條的入?yún)?、響?yīng)、斷言結(jié)果都清晰可見(jiàn)。這就是數(shù)據(jù)驅(qū)動(dòng)的核心價(jià)值用例邏輯只寫(xiě)一次數(shù)據(jù)文件無(wú)限擴(kuò)充回歸成本幾乎為零。5. 斷言的藝術(shù)響應(yīng)斷言、JSON斷言與BeanShell腳本5.1 響應(yīng)斷言和它最容易踩的坑響應(yīng)斷言是大家用得最多的斷言方式但它在做包含匹配的時(shí)候有一個(gè)隱蔽的坑匹配規(guī)則里選“包括”時(shí)是區(qū)分大小寫(xiě)的而且是對(duì)整個(gè)響應(yīng)文本做子串查找。如果你的斷言文本是{code:0}但實(shí)際響應(yīng)是code: 0冒號(hào)后帶空格字符串字面量對(duì)不上斷言會(huì)誤報(bào)失敗。解決辦法是把斷言文本寫(xiě)成更寬松的關(guān)鍵片段比如code:0或者干脆只斷言success這類固定返回詞。另一個(gè)坑是“匹配”規(guī)則。很多人以為選“匹配”就是查找子串其實(shí)不是它要求整個(gè)響應(yīng)文本完全匹配正則表達(dá)式。比如你想用正則code:(\d)但選擇匹配后Jmeter會(huì)用這個(gè)正則去完整匹配整個(gè)響應(yīng)體除非你勾選“字符串”并配合正則捕獲組否則很難用對(duì)。我的建議是早期做功能斷言就無(wú)腦用“包括”別碰“匹配”如果確實(shí)要做復(fù)雜的正則校驗(yàn)就轉(zhuǎn)向斷言響應(yīng)斷言插件或JsonPath相關(guān)的斷言組件。5.2 JSON斷言與JSONPath現(xiàn)在絕大多數(shù)接口返回的是JSON格式這時(shí)候用“響應(yīng)斷言”做子串匹配雖然能用但不夠精準(zhǔn)。比如你只想校驗(yàn)data.total字段是否某項(xiàng)特定數(shù)值用文本匹配還得考慮整個(gè)響應(yīng)體里有沒(méi)有別的地方出現(xiàn)類似字符串容易出現(xiàn)斷言通過(guò)但驗(yàn)證的字段根本不是目標(biāo)字段的情況。Jmeter提供了一個(gè)“JSON斷言”JSON Assertion插件它是基于JsonPath語(yǔ)法來(lái)定位JSON節(jié)點(diǎn)的。JsonPath的入門(mén)記住三條就夠了$表示整個(gè)JSON根節(jié)點(diǎn)$.code表示取根節(jié)點(diǎn)下的code字段$.data.list[0].name表示取data下的list數(shù)組第一個(gè)元素的name字段。語(yǔ)法比XPath簡(jiǎn)單直觀得多。配置方式是添加 - 斷言 - JSON斷言在“JSON Path”欄填$.code在“Expected Value”里填0同時(shí)勾選“JSONPath中存在該節(jié)點(diǎn)”。這樣它會(huì)精確解析JSON結(jié)構(gòu)把code字段的值取出來(lái)和0比較完全不受格式影響。實(shí)際測(cè)試中我甚至?xí)袹SON斷言和響應(yīng)斷言同時(shí)加上響應(yīng)斷言粗粒度驗(yàn)證關(guān)鍵業(yè)務(wù)單詞JSON斷言精粒度校驗(yàn)數(shù)字和結(jié)構(gòu)字段兩者互補(bǔ)基本覆蓋所有接口校驗(yàn)需求。5.3 BeanShell斷言能寫(xiě)代碼就有無(wú)限可能如果你做過(guò)幾年的接口測(cè)試會(huì)發(fā)現(xiàn)很多業(yè)務(wù)校驗(yàn)場(chǎng)景是內(nèi)置斷言組件搞不定的。比如登錄接口返回一個(gè)有效期只有30分鐘的token響應(yīng)里同時(shí)返回token值和過(guò)期時(shí)間戳你想驗(yàn)證“過(guò)期時(shí)間在當(dāng)前時(shí)間30分鐘左右”這個(gè)業(yè)務(wù)規(guī)則這就超出了JSON斷言的能力范圍。這時(shí)候就該上BeanShell斷言了。BeanShell是Jmeter內(nèi)置的腳本語(yǔ)言語(yǔ)法和Java非常相似可以直接在斷言里寫(xiě)邏輯判斷。在取樣器上右鍵添加 - 斷言 - BeanShell斷言在Script區(qū)域?qū)懘a。先講它的核心內(nèi)置變量。prev代表當(dāng)前請(qǐng)求的取樣器結(jié)果對(duì)象通過(guò)prev.getResponseDataAsString()可以拿到整個(gè)響應(yīng)字符串Response等價(jià)于響應(yīng)字符串內(nèi)容直接當(dāng)作String處理Failure是一個(gè)布爾變量設(shè)為true表示斷言失敗FailureMessage是失敗時(shí)輸出的信息。一個(gè)最常用的實(shí)戰(zhàn)例子接口返回JSON格式為{token:abc123,expires_in:1800}我們需要校驗(yàn)token非空且有效期合理。腳本可以這么寫(xiě)import org.json.JSONObject; String response prev.getResponseDataAsString(); JSONObject obj new JSONObject(response); String token obj.optString(token); int expiresIn obj.optInt(expires_in, 0); if (token.isEmpty()) { Failure true; FailureMessage token為空; } if (expiresIn 1000 || expiresIn 2000) { Failure true; FailureMessage expires_in不符合預(yù)期: expiresIn; }注意這里的org.json.JSONObject在Jmeter的lib目錄下自帶不需要額外引入直接用即可。BeanShell斷言適合處理響應(yīng)中的多字段關(guān)聯(lián)校驗(yàn)、日期間隔計(jì)算、復(fù)雜加密邏輯的驗(yàn)證它的上限完全取決于你的Java代碼能力。這也是為什么我說(shuō)Jmeter入門(mén)容易精通難難就難在當(dāng)你需要深度斷言業(yè)務(wù)規(guī)則時(shí)相當(dāng)于要在測(cè)試腳本里寫(xiě)Java代碼。6. 從接口測(cè)試到壓測(cè)同一份腳本如何擴(kuò)展性能場(chǎng)景6.1 接口測(cè)試與壓測(cè)的腳本差異接口測(cè)試腳本和壓測(cè)腳本在本質(zhì)上是同一個(gè)東西差別主要在線程組的配置目標(biāo)和監(jiān)聽(tīng)器選擇上。接口測(cè)試關(guān)心的是功能正確性每個(gè)請(qǐng)求返回的響應(yīng)體是否符合預(yù)期斷言通過(guò)率是否100%。所以線程數(shù)基本設(shè)為1循環(huán)次數(shù)等于測(cè)試用例數(shù)監(jiān)聽(tīng)器選“查看結(jié)果樹(shù)”逐條查看。壓測(cè)關(guān)心的是性能指標(biāo)在高并發(fā)下接口的響應(yīng)時(shí)間、吞吐量、錯(cuò)誤率是否達(dá)標(biāo)。這時(shí)候線程數(shù)要調(diào)大循環(huán)次數(shù)可以設(shè)成永遠(yuǎn)然后配合持續(xù)時(shí)間來(lái)控制執(zhí)行時(shí)長(zhǎng)監(jiān)聽(tīng)器換成聚合報(bào)告或圖形結(jié)果。兩者不是割裂的最佳實(shí)踐是先在功能測(cè)試階段把腳本做到100%通過(guò)斷言全部保留再把同一份腳本復(fù)制一份改成壓測(cè)場(chǎng)景。注意壓測(cè)時(shí)建議把BeanShell斷言和JSON斷言刪掉或注釋掉因?yàn)閿嘌詴?huì)消耗一定的CPU干擾性能數(shù)據(jù)的準(zhǔn)確性只保留響應(yīng)斷言做基本的錯(cuò)誤率判斷即可。6.2 聚合報(bào)告怎么看在線程組下添加監(jiān)聽(tīng)器 - 聚合報(bào)告執(zhí)行完壓測(cè)腳本后它會(huì)匯總出關(guān)鍵指標(biāo)。這個(gè)表格很多人會(huì)看但未必看得透。Samples請(qǐng)求總數(shù)量Average平均響應(yīng)時(shí)間單位毫秒Min / Max最小和最大響應(yīng)時(shí)間Std.Dev響應(yīng)時(shí)間的標(biāo)準(zhǔn)差數(shù)值越大說(shuō)明響應(yīng)波動(dòng)越明顯Error%請(qǐng)求錯(cuò)誤率接口壓測(cè)標(biāo)準(zhǔn)一般要求低于0.1%核心接口要求0%Throughput吞吐量單位是每秒請(qǐng)求數(shù)req/s實(shí)際分析時(shí)不能只看Average還要結(jié)合中位數(shù)和90%或95%響應(yīng)時(shí)間。比如平均響應(yīng)時(shí)間300ms但max是5000ms說(shuō)明有少數(shù)請(qǐng)求特別慢可能是瞬時(shí)線程擁堵或者GC停頓。更專業(yè)的做法是配合“響應(yīng)時(shí)間百分位”監(jiān)聽(tīng)器查看90%、95%和99%分位值這樣能判斷大多數(shù)用戶的真實(shí)體驗(yàn)而不是被極端值影響判斷。6.3 壓測(cè)的節(jié)奏與基本安全操作壓測(cè)最容易犯的錯(cuò)誤是一上來(lái)就把線程數(shù)拉到1000然后系統(tǒng)直接崩潰或者把你自己的電腦跑冒煙。合理的壓測(cè)節(jié)奏應(yīng)該是階梯式增加先20線程跑2分鐘看基線再50線程、100線程、200線程逐步加壓每增加一檔都觀察響應(yīng)時(shí)間和錯(cuò)誤率的變化。當(dāng)錯(cuò)誤率突增或響應(yīng)時(shí)間出現(xiàn)拐點(diǎn)時(shí)那個(gè)線程數(shù)附近就是系統(tǒng)的性能瓶頸區(qū)域。另外壓測(cè)盡量不要在你日常辦公的電腦上直接跑高并發(fā)。Jmeter單機(jī)能模擬的并發(fā)線程數(shù)其實(shí)是有限的每個(gè)線程都是一個(gè)Java線程超過(guò)幾百個(gè)線程后Jmeter自身會(huì)成為性能瓶頸導(dǎo)致測(cè)出來(lái)的數(shù)據(jù)不準(zhǔn)確。更靠譜的做法是部署一臺(tái)單獨(dú)的壓測(cè)機(jī)跑腳本或者用Jmeter分布式模式一個(gè)Master控制多臺(tái)Slave執(zhí)行這已經(jīng)是性能測(cè)試專題的內(nèi)容了這里先給個(gè)結(jié)論單機(jī)跑個(gè)200線程以內(nèi)的壓力驗(yàn)證足夠上生產(chǎn)級(jí)指標(biāo)就要靠分布式。7. 踩坑手冊(cè)HTTPS證書(shū)、上傳文件、中文亂碼與狀態(tài)碼7.1 HTTPS接口和證書(shū)問(wèn)題現(xiàn)在接口大部分是HTTPS協(xié)議第一次請(qǐng)求時(shí)Jmeter會(huì)拋出證書(shū)信任錯(cuò)誤因?yàn)镴meter自帶的證書(shū)庫(kù)不信任被測(cè)系統(tǒng)的自簽名證書(shū)。解決辦法是讓Jmeter“自己信任自己”它有一個(gè)內(nèi)置的代理證書(shū)機(jī)制。打開(kāi)bin目錄下的ApacheJMeterTemporaryRootCA.crt雙擊安裝到系統(tǒng)的受信任的根證書(shū)頒發(fā)機(jī)構(gòu)即可或者更省事的辦法是在HTTP請(qǐng)求下方勾選“使用”Use KeepAlive旁邊的“使用”選項(xiàng)卡里下面的Implementation選HttpClient4然后在bin目錄修改jmeter.properties文件把server.rmi.ssl.disablefalse改成true只是針對(duì)分布式針對(duì)SSL證書(shū)信任在jmeter.properties里修改jmeter.https.certmanager相關(guān)的注釋項(xiàng)通常不如直接安裝CA高效。我實(shí)際最常用的做法是在bin目錄下找到curl或直接命令行用openssl s_client導(dǎo)出目標(biāo)域名的證書(shū)然后導(dǎo)入Jmeter的cacert這在接口比較穩(wěn)定只是偶爾用Jmeter測(cè)的時(shí)候比較方便。最傻瓜的方式是安裝ApacheJMeterTemporaryRootCA.crt如果仍然報(bào)錯(cuò)再檢查JDK的cacerts庫(kù)里有沒(méi)有Jmeter證書(shū)keytool -list -keystore cacerts可以查看。這里不展開(kāi)命令細(xì)節(jié)記住一條原則HTTPS證書(shū)問(wèn)題90%可以通過(guò)安裝Jmeter根證書(shū)解決剩下的10%屬于JDK版本或雙向TLS認(rèn)證需要走代碼層處理。7.2 上傳文件接口怎么配置文件上傳接口用Jmeter做測(cè)試很多人第一次都摸不著頭腦。HTTP請(qǐng)求里其實(shí)有一塊專門(mén)的文件上傳區(qū)域在HTTP請(qǐng)求取樣器下方找到“Files Upload”區(qū)塊配置文件名要上傳的本地文件路徑、參數(shù)名稱對(duì)應(yīng)接口文檔里的文件字段名、MIME類型比如image/png、application/octet-stream。注意一定要把HTTP請(qǐng)求的方法改為POST并且在HTTP信息頭管理器里不要手動(dòng)設(shè)置Content-Type因?yàn)槲募蟼魇莔ultipart/form-data格式Jmeter會(huì)自動(dòng)生成帶boundary分隔線的Content-Type頭你手動(dòng)設(shè)置了反而會(huì)被覆蓋導(dǎo)致服務(wù)端解析失敗。還要確認(rèn)HTTP請(qǐng)求下方的“Use multipart/form-data for POST”選項(xiàng)勾選上否則Jmeter可能按普通表單方式提交接口收不到文件流。如果是多個(gè)文件同時(shí)上傳就讓它逐行配置多個(gè)文件字段注意參數(shù)名保持一致服務(wù)端用同一個(gè)字段接收多文件。上傳后通過(guò)響應(yīng)JSON判斷是否成功比如返回文件URL或文件ID不要只看200。7.3 中文亂碼問(wèn)題排查接口返回的中文變成\u5f00\u59cb或者直接問(wèn)號(hào)原因通常是響應(yīng)內(nèi)容的編碼和Jmeter默認(rèn)的ISO-8859-1不一致。最高效的解決方式是把bin目錄下jmeter.properties文件的sampler.encoding改成UTF-8取消注釋后重啟Jmeter這樣絕大多數(shù)JSON中文問(wèn)題都能解決。如果改了還是亂碼則需要在HTTP請(qǐng)求取樣器的“Http Request”里勾選“對(duì)響應(yīng)使用配置文件的編碼”或者直接在后置處理器里寫(xiě)B(tài)eanShell處理String response prev.getResponseDataAsString(); String utf8 new String(response.getBytes(ISO-8859-1), UTF-8);這個(gè)方法治標(biāo)不治本但是實(shí)在找不到改配置入口時(shí)的應(yīng)急方案。另外做參數(shù)化時(shí)CSV文件里面的中文讀取出來(lái)也是亂碼那就不是響應(yīng)編碼問(wèn)題而是CSV文件的編碼不對(duì)要在CSV數(shù)據(jù)文件設(shè)置里把文件編碼改成UTF-8或GBK對(duì)應(yīng)即可。7.4 常見(jiàn)HTTP狀態(tài)碼在實(shí)際測(cè)試中的定位思路接口測(cè)試跑完結(jié)果樹(shù)看到一堆4xx、5xx狀態(tài)碼怎么快速定位是哪個(gè)環(huán)節(jié)出了問(wèn)題這里給一個(gè)我自己的排查思路表狀態(tài)碼含義排查方向200請(qǐng)求成功仍需看業(yè)務(wù)code不代表邏輯一定正確400請(qǐng)求參數(shù)錯(cuò)誤檢查Header的Content-Type和Body格式401未認(rèn)證檢查token是否傳錯(cuò)、是否過(guò)期403無(wú)權(quán)限檢查用戶角色和數(shù)據(jù)權(quán)限404路徑不存在檢查URL路徑和協(xié)議頭是否寫(xiě)錯(cuò)405方法不允許接口要求GET但你發(fā)了POST415不支持的媒體類型Content-Type設(shè)置和服務(wù)端不一致500服務(wù)端內(nèi)部錯(cuò)誤大概率是服務(wù)端邏輯或參數(shù)格式觸發(fā)了異常502/504網(wǎng)關(guān)超時(shí)或錯(cuò)誤服務(wù)端出異?;蚝蠖朔?wù)掛了遇到500錯(cuò)誤時(shí)優(yōu)先去服務(wù)端日志看異常堆棧這是最快的方式。如果測(cè)的是第三方接口拿不到服務(wù)端日志就重放請(qǐng)求并簡(jiǎn)化參數(shù)逐步排查是哪個(gè)參數(shù)引發(fā)了異常。我之前在測(cè)試中就遇到過(guò)明明傳參格式都對(duì)但服務(wù)端把status: 1誤判為開(kāi)啟、status: 0誤判為關(guān)閉這種字段語(yǔ)義理解問(wèn)題結(jié)果接口返回500這類坑只能靠溝通和對(duì)接口文檔的反復(fù)確認(rèn)來(lái)解決。最后再補(bǔ)充一個(gè)實(shí)際工作中的心得Jmeter雖然歷史悠久界面也不算好看但勝在生態(tài)成熟、組件全、資料多不管你是做接口功能驗(yàn)證、批量數(shù)據(jù)回歸還是性能摸底它都能扛住。我個(gè)人現(xiàn)在的工作流是Postman負(fù)責(zé)開(kāi)發(fā)階段的快速調(diào)試Jmeter負(fù)責(zé)正式環(huán)境的接口回歸和后續(xù)壓測(cè)兩者不沖突反而互相彌補(bǔ)。如果你剛開(kāi)始學(xué)別急著研究所有組件先把線程組、HTTP請(qǐng)求、查看結(jié)果樹(shù)、CSV參數(shù)化、響應(yīng)斷言這五個(gè)核心用熟就能覆蓋日常80%的接口測(cè)試場(chǎng)景剩下的遇到具體需求再針對(duì)性深挖。