这是测试的项目结构,具体每个文件夹是用来做什么,我在前面的项目搭建里面提到过,这里就不赘述了。
properties file(包含一些基本的属性信息,例如baseUR,用户名密码之类的)
baseUrl=https://ome.uat.ome-staging.eurekacloud.io/
loginUri=auth/openid/login?provider=
logoutUri=auth/logout
authUser=auth/user
csrfToken=auth/csrf-token
inputRegEx=<input(.*?) name(.*?)"([^"]*)"(.*?) value(.*?)"([^"]*)"(.*?)>|<input(.*?) name(.*?)'([^']*)'(.*?) value(.*?)'([^']*)'(.*?)>
aRegEx=<a(.*?) href(.*?)"([^"]*)"(.*?)>
formRegEx=<form(.*?) action(.*?)"([^"]*)"(.*?)>
metaRegEx=<meta name="csrf-token" content(.*?)"([^"]*)"(.*?)>
customerId=9100021
deletionSecret=Bl@ck$heep
adminUser=ya.wu001@aaa.com
adminPassword=Initial00
测试数据文件,我这里是包含不同visit ID的用户,这个文件一般是放在data目录下
新建API测试文件: 文件路径是 src-scala-apitests
package apitests
import io.gatling.core.Predef._
import io.gatling.core.structure.ChainBuilder
import io.gatling.http.Predef._
import java.util.Properties
import scala.io.Source
class VisitExecution(properties: Properties) {
//读取property文件的baseURl
val baseURL: String = properties.getProperty("baseUrl")
var api = ""
//读取测试数据指定字段的值
def getVisitID(): ChainBuilder = {
exec(session => {
var visitID = ""
visitID = session("VisitBizId").as[String]
//set方法设置key,后面的请求里面都可以直接引用这个key直接获取到对应的值
session.set("visitBizId", visitID)
})
}
// url请求测试
def getSpecifiedVisit(): ChainBuilder = {
api = "api/ome-visit-execution/business/v1/visit-execution/visits/${visitBizId}"
println(baseURL + api)
exec(
// 新建http请求,这里定义的请求名字(Eg:GetVisit),最后会在Report里面显示,所以最好定义清楚一点
http("GetVisit " + api)
// get发送get请求,还有post、put、delete
.get(baseURL + api)
// header方法设置header
.header("x-csrf-token", "${csrfToken}")
.header("Content-Type", "application/json")
// check方法检测 status.is方法检测responseStatus是否是期待值
.check(status.is("200"))
// status.saveAs方法把获取的Status设置成key
.check(status.saveAs(key = "responseStatus"))
// checkif方法是判断条件,类似于java中if(a=100){ print("a")},这里是用来检测responseBody是否符合预期结果,同时还可以保存结果,以供后面的API调用
.check(checkIf(session => session("responseStatus").as[Int] == 200) {
jsonPath("$.visitBizId").saveAs("visitBizId")
})
.check(checkIf(session => session("responseStatus").as[Int] == 200) {
jsonPath("$.activityList[?(@['title' ]=='TestPerformanceQuestion')]. activityId").saveAs("questionActivityId")
})
.check(checkIf(session => session("responseStatus").as[Int] == 200) {
jsonPath("$.activityList[?(@['title' ]=='TestPerformanceTask')]. activityId").saveAs("taskActivityId")
})
)
.exec { session =>
// 打印前面保存的key,Gatling + Maven的测试一般不是很好debug,所以通常使用打印log的方式来debug
println("%dGet a specified visit status: %s".format(System.currentTimeMillis(), session("responseStatus").as[String]))
println("%dGet a specified visit visitBizId: %s".format(System.currentTimeMillis(), session("visitBizId").as[String]))
println("%dGet a specified visit questionActivityId: %s".format(System.currentTimeMillis(), session("questionActivityId").as[String]))
println("%dGet a specified visit taskActivityId: %s".format(System.currentTimeMillis(), session("taskActivityId").as[String]))
session
}
}
def runSmokeTests(): ChainBuilder = {
// 把需要测试的API放到一个Group里面,这样最后是生成的Report会按照Group划分,括号里面输入group的名字,最后会显示在Report上面
group("Visit Execution:") {
exec(getVisitID())
.exec(getSpecifiedVisit())
}
}
}
创建Simulation文件,文件路径src-scala-simulations
package simulations
import java.util.Properties
import apitests.VisitExecution
import io.gatling.core.Predef._
import io.gatling.core.feeder.BatchableFeederBuilder
import io.gatling.core.structure.{ChainBuilder, ScenarioBuilder}
import io.gatling.http.Predef.http
import io.gatling.http.protocol.HttpProtocolBuilder
import utils.XsuaaLogin
import scala.io.{BufferedSource, Source}
class OMEE2ESmokeTest extends Simulation {
var env: String = sys.env("TEST_TARGET")
println(s"Environment : $env")
val properties: Properties = new Properties()
// 读取properties文件
val source: BufferedSource = Source.fromFile(s"src/test/resources/config/env_${env}.properties")
println(s"src/test/resources/config/env_${env}.properties")
properties.load(source.bufferedReader())
val baseURL: String = properties.getProperty("baseUrl")
// 读取测试数据文件
var feeder: BatchableFeederBuilder[String]#F = csv(s"data/OMEOutletManagementExecution_ome-test2.csv").circular
val httpConf: HttpProtocolBuilder = http.baseUrl(url = baseURL)
val login: XsuaaLogin = new XsuaaLogin(properties)
// 设置测试用户数
val user_number: Int = sys.env("USER_NUMBER").toInt
// 调用你的测试方法
val ve: VisitExecution = new VisitExecution(properties)
def runTests(): ChainBuilder = {
// Gatling里面feeder的概念就是测试数据的意思,意思是这组测试你的测试数据文件是来自于这个feeder
feed(feeder)
.exec(login.loginAdmin())
.exec(ve.runSmokeTests())
}
//在指定的Scenario里面运行你的测试用例,同时定义你的测试场景名称,gatling是支持运行多个scenario的
val scn: ScenarioBuilder = scenario("OME E2E Smoke Test - API")
.exec(runTests())
//这里设置性能测试的用户数,Gatling有不同的注入用户的方式,这里举例是一次性注入,一般性能测试会在jenkins job上跑,所以这里的参数是读取的环境变量,你也可以直接指定成你需要的数量
setUp(scn.inject(atOnceUsers(users=user_number))
).protocols(httpConf)
}
运行simulation文件,gatling默认是不支持一次性运行多个simulation文件,但是我们实际测试场景是需要一些准备数据的操作步骤,所以这里提供一个小脚本,有多个测试文件需要运行时可以通过逗号分开,自己保存成sh文件,然后在terminal中输入命令运行测试:
./run.sh -s ${Simulation Array} ${Target Test Enviroment} ${User Number}
eg: $ ./run.sh -s OMELoginTest,RolePermissionApiTests ome-test 1
#!/bin/bash
#params
SIMULATION_CLASSES=
#usage
function usage (){
echo "usage: $0 options"
echo "This script run Gatling load tests"
echo ""
echo "OPTIONS:"
echo "Run options:"
echo " -s [*] Simulation classes (comma separated)"
}
echo "test_target=$3"
echo "user_number=$4"
#INIT PARAMS
while getopts "s:" OPTION
do
case $OPTION in
s) SIMULATION_CLASSES=$OPTARG;;
?) usage
exit 1;;
esac
done
#checks
if [[ -z $SIMULATION_CLASSES ]]; then
usage
exit 1
fi
#run scenarios
export TEST_TARGET=$3
export USER_NUMBER=$4
SIMULATION_CLASSES_ARRAY=($(echo $SIMULATION_CLASSES | tr "," "\n"))
mvn compile
for SIMULATION_CLASS in "${SIMULATION_CLASSES_ARRAY[@]}"
do
echo "Run scenario for $SIMULATION_CLASS"
mvn gatling:test -Dgatling.simulationClass=simulations.$SIMULATION_CLASS
done