Gatling 自動(dòng)化壓測(cè)&Jmeter

Gatling是一款基于Scala 開發(fā)的高性能服務(wù)器性能測(cè)試工具,它主要用于對(duì)服務(wù)器進(jìn)行負(fù)載等測(cè)試;想使用Gatling進(jìn)行壓測(cè)的原因之一是想體驗(yàn)一下Scala編程的感覺(jué),玩一下;第二,工作上也確實(shí)有這樣的需求;

壓測(cè)工作簡(jiǎn)單來(lái)說(shuō)就是利用壓測(cè)應(yīng)用,來(lái)測(cè)試一下服務(wù)器的響應(yīng)性能參數(shù);然后把這些工作全部自動(dòng)化,集成到j(luò)enkins中來(lái)運(yùn)行。

整個(gè)工作的子任務(wù)分解可以由下圖來(lái)表示:

壓測(cè)使用的是一個(gè)常見(jiàn)的web應(yīng)用,該web應(yīng)用的具體使用的業(yè)務(wù)場(chǎng)景如下:

針對(duì)該應(yīng)用的壓測(cè)Scala源代碼如下:
文件名:performance.scala

package performance

import scala.concurrent.duration._

import io.gatling.core.Predef._
import io.gatling.http.Predef._
import io.gatling.jdbc.Predef._

class Performance extends Simulation {

  //用戶名、餐館ID 存儲(chǔ)文件
  val user = csv("/root/.jenkins/workspace/testGatling/src/test/scala/data/user.csv").random
  val res = csv("/root/.jenkins/workspace/testGatling/src/test/scala/data/restaurant.csv").random
  val ip = csv("/root/.jenkins/workspace/testGatling/src/test/scala/data/ip.csv").random

  val httpProtocol = http
    .baseURL("http://${ip}:8180")

  val headers_0 = Map("Accept" -> "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8")

  val scn = scenario("Emenu")
    //打開訂餐首頁(yè)
    .exec(http("index")
    .get("/E_Menu/userlogin/login.jsp")
    .headers(headers_0))

    //登錄
    .pause(1 second,20 second)
    .feed(user)
    .feed(res)
    .exec(http("login")
    .post("/E_Menu/userlogin/login")
    .headers(headers_0)
    .formParam("username", "${username}")
    .formParam("password", "${password}")
    )

    //選擇餐館
    .pause(1 second,20 second)
    .exec(http("menu")
    .get("/E_Menu/menu.action?res_num=${rest_id}")
    .headers(headers_0)
    )
    //點(diǎn)菜
    .pause(1 second,20 second)
    .exec(addCookie(Cookie("username", "${username}")))
    .exec(addCookie(Cookie("res_num", "${rest_id}")))
    .exec(addCookie(Cookie("food_num0", "105")))
    .exec(addCookie(Cookie("food_num1", "104")))
    .exec(addCookie(Cookie("food_num2", "104")))
    .exec(addCookie(Cookie("food_num3", "106")))
    .exec(addCookie(Cookie("total", "52")))
    .exec(http("list") //點(diǎn)完菜,開始訂
    .get("/E_Menu/list.action")
    .headers(headers_0)
    )
    //下單
    .pause(1 second,20 second)
    .exec(http("order")
    .get("/E_Menu/order.action?people=5&time=2025-08-31")
    .headers(headers_0)
    )

    //    //回首頁(yè)
    .pause(1 second,20 second)
    .exec(http("restaurant")
    .get("/E_Menu/restaurant.action")
    .headers(headers_0)
    )

    //用戶信息
    .pause(1 second,20 second)
    .exec(http("userinfo")
    .get("/E_Menu/userinfo?username=${username}")
    .headers(headers_0)
    )

    //我的訂單
    .pause(1 second,20 second)
    .exec(http("userorder")
    .get("/E_Menu/userorder.action?username=${username}")
    .headers(headers_0)
    )

    //退出
    .pause(1 second,20 second)
    .exec(http("exit")
    .get("/E_Menu/userlogin/login.jsp")
    .headers(headers_0))

  setUp(scn.inject(atOnceUsers(100))).protocols(httpProtocol)
}

寫完scala代碼,并且保證它在本地可以調(diào)試通過(guò),下一步就是需要將代碼集成進(jìn)jenkins;
先確保jenkins Gatling Plugin在jenkins上被安裝;
之后,寫入用來(lái)執(zhí)行的shell調(diào)控代碼:

#################### 環(huán)境準(zhǔn)備 ####################
pwd
export IP="xx.xx.xx.xx"
export user="root"
export pwd="xxxxxxxxxx"
export tomcat_path="/root/apache-tomcat-7.0.56/bin"
export killtomcat="/root/killtomcat.sh"

#################### 定義函數(shù) ####################
kill_tomcat7(){
expect -c "
spawn ssh $user@$IP sh $killtomcat;
expect {
yes/no { send yes\r;exp_continue }
*password: { send $pwd\r }
};
expect eof;
"
}

start_tomcat(){
expect -c "
spawn ssh $user@$IP sh $tomcat_path/$1;
expect {
yes/no { send yes\r;exp_continue }
*password: { send $pwd\r }
};
expect eof;
"
}
#################### tomcat壓測(cè) ####################

停止tomcat

kill_tomcat7

啟動(dòng)tomcat

start_tomcat startup_non.sh

mvn gatling:execute -Dgatling.simulationClass=performance.Performance

#################### 完畢 ####################

參考截圖如下:

在完成調(diào)試改bug工作之后,可以嘗試運(yùn)行一下,得到壓測(cè)結(jié)果 Gatling report ,然后可以進(jìn)行相關(guān)的數(shù)據(jù)分析,這里不再贅述。
Jenkins 集成 Gatling Report參考截圖如下:

11 個(gè)贊 關(guān)注 收藏

所以具體實(shí)現(xiàn)過(guò)程我這里不多寫了,我重點(diǎn)寫下對(duì)生成的HTML測(cè)試報(bào)告進(jìn)行優(yōu)化。

如果按JMeter默認(rèn)設(shè)置,生成報(bào)告如下:

從上圖可以看出,結(jié)果信息比較簡(jiǎn)單,對(duì)于運(yùn)行成功的case,還可以將就用著。但對(duì)于跑失敗的case,就只有一行assert錯(cuò)誤信息。(信息量太少了,比較難找到失敗原因)

優(yōu)化大致過(guò)程

1、修改jmeter.properties文件,打開一些輸出內(nèi)容開關(guān)(下圖根據(jù)需要選擇相關(guān)項(xiàng),具體就不用多說(shuō)了吧)

2、制定一份自己的輸出模板。(不用默認(rèn)的jmeter_home/extras/jmeter-results-detail-report.xsl模板,也可以網(wǎng)上自己找份。)
3、最后執(zhí)行,生成對(duì)應(yīng)的HTML報(bào)告(一般我們都在linux環(huán)境 下運(yùn)行,語(yǔ)句大致如下,其中my_project_template.xsl就上第2步說(shuō)的定制模板,這個(gè)是網(wǎng)上找的一份。)

xsltproc $jmeter_home/extras/my_project_template.xsl $my_project_workspace/result/jtl/$test_name/${test_name}.jtl > $my_project_workspace/result/html/$test_name/${test_name}.html

最后報(bào)告如下:

優(yōu)化后的HTML報(bào)告,多了接口地址、接口參數(shù)、Headers信息(包括cookie、session),而且有返回結(jié)果。失敗原因一目了然[圖片上傳失敗...(image-9cb8f5-1527240193077)]

最后附上我的jmeter文件樣本:

什么是mock server

mock:英文可以翻譯為模仿的,mock server是我們用來(lái)解除依賴(耦合),假裝實(shí)現(xiàn)的技術(shù),比如說(shuō),前端需要使用某些api進(jìn)行調(diào)試,但是服務(wù)端并沒(méi)有開發(fā)完成這些api,那么前端的工作就被服務(wù)端阻塞了,那么就可以使用mock server假裝實(shí)現(xiàn)這些api,能夠返回特定的數(shù)據(jù),幫助前端進(jìn)行頁(yè)面渲染,當(dāng)然我們?yōu)榱朔奖憧梢孕枰c服務(wù)端進(jìn)行約定,約定接口的內(nèi)容是什么。

restful接口規(guī)范

轉(zhuǎn)接阮一峰老師的博客—RESTful API 設(shè)計(jì)指南:http://www.ruanyifeng.com/blog/2014/05/restful_api.html

Moco-約定uri(一)

moco工具是在github開源的一個(gè)項(xiàng)目,可以使用moco工具搭一個(gè)簡(jiǎn)單的mock server方便我們進(jìn)行調(diào)試,github地址:https://github.com/dreamhead/moco,下載下來(lái)的是一個(gè)jar包,目前的版本是0.11.1,首先我們要編寫一個(gè)config文件,把我們需要“模擬”的請(qǐng)求和響應(yīng)寫入這個(gè)配置文件,配置文件是json格式的,接下來(lái)我們寫一個(gè)比較簡(jiǎn)單的請(qǐng)求,訪問(wèn) localhost:12306/hello 接口,返回一個(gè)純文本“moco”,moco工具約定了12306端口,不必糾結(jié),就跟tomcat約定8080端口類似,config.json文件如下,而且json文件要與moco的jar包放在同一個(gè)文件夾下。比如博主的目錄結(jié)構(gòu):

G:\學(xué)習(xí)資料\mock\moco-runner-0.11.1-standalone.jar
G:\學(xué)習(xí)資料\mock\config.json

[
    {
        "request":
        {
            "uri":"/hello"
        },
        "response":
        {
            "text":"moco"
        }
    }
]

配置文件比較簡(jiǎn)單,我們請(qǐng)求接口,返回一個(gè)純文本,啟動(dòng)指令:

>java -jar moco-runner-0.11.1-standalone.jar http -p 12306 -c config.json

這里的http就是http協(xié)議, -p 12306 綁定端口號(hào)12306, -c config.json讀config文件

這里寫圖片描述

看到以上的表現(xiàn),就說(shuō)明moco已經(jīng)順利啟動(dòng)了,我們?cè)L問(wèn)localhost:12306/hello 看到結(jié)果如下就說(shuō)明mock server順利返回了我們約定的數(shù)據(jù)”moco”


這里寫圖片描述

Moco-約定uri(二)

修改config文件如下,注意這里moco工具能實(shí)時(shí)監(jiān)測(cè)到j(luò)son配置文件的變化,并自行重啟server


這里寫圖片描述
[
    {
        "request":
        {
            "uri":"/"
        },
        "response":
        {
            "text":"welcome to Moco"
        }
    },
    {
        "request":
        {
            "uri":"/hello"
        },
        "response":
        {
            "text":"moco"
        }
    }
]

接下來(lái)分別訪問(wèn)localhost:12306和12306:12306/hello,結(jié)果如下:


這里寫圖片描述
這里寫圖片描述

Moco-約定get請(qǐng)求

[
    {
        "request":
        {
            "method":"get",
            "uri":"/get"
        },
        "response":
        {
            "text":"moco get"
        }
    }
]

Moco-約定post請(qǐng)求

[
    {
        "request":
        {
            "method":"post",
            "uri":"/post"
        },
        "response":
        {
            "text":"moco post"
        }
    }
]

Moco-約定請(qǐng)求參數(shù)

[
    {
        "request":
        {
            "method":"get",
            "uri":"/get",
            "queries":
            {
                "id":"12306",
                "name":"moco"
            }
        },
        "response":
        {
            "text":"moco queries"
        }
    }
]
這里寫圖片描述

Moco-約定請(qǐng)求body必須為json格式

[
    {
        "request":
        {
            "method":"post",
            "uri":"/post",
            "text":
            {
                "json":"{\"id\":\"12306\",\"name\":\"moco\"}"
            }
        },
        "response":
        {
            "status":"200"
        }
    }
]

Moco-約定請(qǐng)求頭部

[
    {
        "request":
        {
            "method":"post",
            "uri":"/post",
            "headers":
            {
                "content-type":"application/json",
                "Connection":"keep-alive",
                "Content-Encoding":"gzip"
            }
        },
        "response":
        {
            "status":"200"
        }
    }
]

Moco-約定返回內(nèi)容

前面已經(jīng)看到了response的集中返回內(nèi)容如text,和status,下面展示一下返回文件和設(shè)置文件格式等

[
    {
        "request":
        {
            "method":"post",
            "uri":"/post",
        },
        "response":
        {
            "file":"data.js",
            "charset":"GBK",
            "version":"HTTP/1.0"
        }
    }
]

Moco-約定返回狀態(tài)碼

見(jiàn)上述的幾個(gè)json,里面已經(jīng)包含了返回狀態(tài)碼的使用方式

Moco-在單元測(cè)試中的使用(以Python為例)

[
    {
        "request":
        {
            "method":"get",
            "uri":"/api/hello"
        },
        "response":
        {
            "text":"hello Savitar!",
            "status":200
        }
    }
]

這里模擬一個(gè)get請(qǐng)求,返回純文本“hello Savitar!”和狀態(tài)碼200,先在瀏覽器訪問(wèn)localhost:12306/api/hello 結(jié)果如下圖:


這里寫圖片描述

說(shuō)明接口返回沒(méi)問(wèn)題,接下來(lái)使用Python requests+unittest寫一個(gè)簡(jiǎn)單的接口測(cè)試用例


#coding=utf-8
'''
@author=Savitar
'''
import unittest
import requests

class MocoTestApi(unittest.TestCase):
    def setUp(self):
        self.url = "http://localhost:12306"
    def test_moco_test_api(self):
        api = "/api/hello"
        url = self.url+api
        r = requests.get(url)
        self.assertEqual(r.status_code,200)
        self.assertEqual(r.text,"hello Savitar!")
    def tearDown(self):
        pass

if __name__ == '__main__':
    unittest.main()
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容