当前位置:网站首页>Gatling performance test
Gatling performance test
2022-06-24 13:48:00 【Or turn around】
Gatling It's based on AKKA and Netty Developed high-performance pressure measuring tools , Very simple to use .
Overview and use
Gatling You can download it directly , It can also be done through maven Plug ins are integrated in the project , Execute... From the command line .
See the official website for direct use ( See references 1). Here we introduce how to use maven Plug in to use .
gatling-maven-plugin
First, we introduce dependency packages , This is required by the test script :
<dependency>
<groupId>io.gatling.highcharts</groupId>
<artifactId>gatling-charts-highcharts</artifactId>
<version>MANUALLY_REPLACE_WITH_LATEST_VERSION</version>
<scope>test</scope>
</dependency>
Then introduce the dependent plug-ins :
<plugin>
<groupId>io.gatling</groupId>
<artifactId>gatling-maven-plugin</artifactId>
<version>MANUALLY_REPLACE_WITH_LATEST_VERSION</version>
</plugin>
It is best to specify an explicit plug-in version . If you do not specify the plug-in version , The system will automatically find the latest version , This may not guarantee that the build is repeatable . Because there is no guarantee that the future behavior of the plug-in will be consistent with the current .
about Scala development , from 4.x Version start , The plug-in is no longer compiled Scala Code , If the test class uses scala To write it , You must use scala-maven-plugin Plug in to replace .
For convenience , This article is based on the project code created above . Add a new one hello-world-test-perform Sub module , Specially used for load testing .
stay test Create test class under package BasicSimulation:
import io.gatling.javaapi.core.*;
import io.gatling.javaapi.http.*;
import static io.gatling.javaapi.core.CoreDsl.*;
import static io.gatling.javaapi.http.HttpDsl.*;
public class BasicSimulation extends Simulation {
public final String hostname = System.getProperty("url");
HttpProtocolBuilder httpProtocol = http
.baseUrl(hostname)
.acceptHeader("text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8")
.doNotTrackHeader("1")
.acceptLanguageHeader("en-US,en;q=0.5")
.acceptEncodingHeader("gzip, deflate")
.userAgentHeader("Mozilla/5.0 (Windows NT 5.1; rv:31.0) Gecko/20100101 Firefox/31.0");
ScenarioBuilder scn = scenario("HelloWorldSimulation")
.exec(http("request_1").get("/data/hello"))
.pause(5);
{
// Inject users , At the beginning, there was one , Agreement is http
setUp(scn.injectOpen(atOnceUsers(1))).protocols(httpProtocol);
}
}
among ,hostname It's taken from the system variables , This is in plugin Configured in :
<plugin>
<groupId>io.gatling</groupId>
<artifactId>gatling-maven-plugin</artifactId>
<configuration>
<skip>${skipLTandPTs}</skip>
<jvmArgs>
<jvmArg>-Durl=${testTarget}</jvmArg>
</jvmArgs>
</configuration>
<executions>
<execution>
<phase>test</phase>
<goals>
<goal>test</goal>
</goals>
</execution>
</executions>
</plugin>
In this plug-in skipLTandPTs and testTarget Parameters are inherited from the parent file . The parent file pom.xml The configuration is as follows :
...
<profiles>
<profile>
<id>local</id>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
<properties>
<environment>dev</environment>
<testTarget>http://localhost:8080/tt</testTarget>
</properties>
</profile>
<profile>
<id>pt</id>
<properties>
<skipTests>true</skipTests>
<skipLTandPTs>false</skipLTandPTs>
</properties>
</profile>
</profiles>
such , function hello-world After the project , Execute on the command line :
mvn clean test -P local,pt
Load test can be carried out . The generated results are placed in by default target/gatling Under the table of contents , Access in a browser index.html as follows :
Basic concepts
gatling The main objects in include :Simulation,Injection,Scenario,Session etc. .
Simulation
setUp
setUp yes Simulation A necessary part of :
ScenarioBuilder scn = scenario("scn"); // etc...
{
setUp(
scn.injectOpen(atOnceUsers(1))
);
}
Protocol configuration
The protocol configuration can be written in setUp Method outside , Indicates that it is effective for all scenarios ; It can also be written on every scene , Indicates that it is effective for the current scene . As shown below :
// HttpProtocol configured globally
setUp(
scn1.injectOpen(atOnceUsers(1)),
scn2.injectOpen(atOnceUsers(1))
).protocols(httpProtocol);
// different HttpProtocols configured on each population
setUp(
scn1.injectOpen(atOnceUsers(1))
.protocols(httpProtocol1),
scn2.injectOpen(atOnceUsers(1))
.protocols(httpProtocol2)
);
Acceptance conditions
The acceptance conditions determine whether the load test can pass , stay setUp Method configuration .
setUp(scn.injectOpen(atOnceUsers(1)))
.assertions(global().failedRequests().count().is(0L));
setUp(scn.injectOpen(atOnceUsers(1)))
.assertions(
global().responseTime().mean().lt(2000),
global().successfulRequests().percent().gt(99.0)
);
Scenario
The scene name can be except \t Any character other than :
ScenarioBuilder scn = scenario();
exec
exec Method is used to perform simulated interface calls , Support HTTP,LDAP,POP,IMAP Such agreement .
Here is HTTP An example of a simulated request for a protocol :
// Bound to the scenario
scenario("Scenario")
.exec(http("Home").get("https://gatling.io"));
// Create directly for subsequent reference
ChainBuilder chain = exec(http("Home").get("https://gatling.io"));
// Bind to other
exec(http("Home").get("https://gatling.io"))
.exec(http("Enterprise").get("https://gatling.io/enterprise"));
exec It can also be used for transfer functions . This feature makes it easy to set up and debug Session:
exec(session -> {
// displays the content of the session in the console (debugging only)
System.out.println(session);
// return the original session
return session;
});
exec(session ->
// return a new session instance
// with a new "foo" attribute whose value is "bar"
session.set("foo", "bar")
);
pause
Usually , When a user browses a page , There will be a time interval between the two operations . To simulate this behavior ,gatling Improved pause method .
Here are some ways to use :
The pause time is fixed
pause(10); // with a number of seconds
pause(Duration.ofMillis(100)); // with a java.time.Duration
pause("#{pause}"); // with a Gatling EL string resolving to a number of seconds or a java.time.Duration
pause(session -> Duration.ofMillis(100)); // with a function that returns a java.time.Duration
Temporally random
pause(10, 20); // with a number of seconds
pause(Duration.ofMillis(100), Duration.ofMillis(200)); // with a java.time.Duration
pause("#{min}", "#{max}"); // // with a Gatling EL strings
pause(session -> Duration.ofMillis(100), session -> Duration.ofMillis(200)); // with a function that returns a java.time.Duration
loop
repeat
If a request occurs repeatedly , Can pass repeat To simulate the .
// with an Int times
repeat(5).on(
exec(http("name").get("/"))
);
// with a Gatling EL string resolving an Int
repeat("#{times}").on(
exec(http("name").get("/"))
);
// with a function times
repeat(session -> 5).on(
exec(http("name").get("/"))
);
// with a counter name
repeat(5, "counter").on(
exec(session -> {
System.out.println(session.getInt("counter"));
return session;
})
);
Traverse
Each element in the list can be executed in the specified order action. There are three main parameters :
- seq: A sequence of elements to traverse , It can be a list or Gatling EL Expression or function
- elementName:key
- counterName( Optional ): Cycle counter , from 0 Start
// with a static List
foreach(Arrays.asList("elt1", "elt2"), "elt").on(
exec(http("name").get("/"))
);
// with a Gatling EL string
foreach("#{elts}", "elt").on(
exec(http("name").get("/"))
);
// with a function
foreach(session -> Arrays.asList("elt1", "elt2"), "elt").on(
exec(http("name").get("/"))
);
// with a counter name
foreach(Arrays.asList("elt1", "elt2"), "elt", "counter").on(
exec(session -> {
System.out.println(session.getString("elt2"));
return session;
})
);
There are other loop operations , Here is not a list .
Error handling
tryMax
tryMax You can specify the number of retries , When action When execution fails , Will try again .
tryMax(5).on(
exec(http("name").get("/"))
);
// with a counter name
tryMax(5, "counter").on(
exec(http("name").get("/"))
);
exitBlockOnFail
Fail to exit immediately :
exitBlockOnFail(
exec(http("name").get("/"))
);
exitHere
Specify the virtual user from scenario sign out :
exitHere();
exitHereIf
Exit according to conditions :
exitHereIf("#{myBoolean}");
exitHereIf(session -> true);
Injection
Use injectOpen and injectClosed Method to define the injection configuration information of the user ( And Scala Medium inject The same effect ), The method parameters are a series of injection steps , It is also processed in sequence .
Open and Closed Workload model
When it comes to load models , There are usually two types of systems :
- Closed System , It can be used to control the number of concurrent users
- Open System , It can be used to control the arrival rate of users
There is an upper limit on the number of concurrent users in a closed system , When the concurrency reaches the upper limit , Only when a user exits , New users can enter the system .
This is similar to the thread pool working mode , When the worker thread is full , New requests enter the task queue , Wait for a thread to be idle before proceeding .
The ticketing business system generally needs to adopt a closed model .
The closed model is suitable for systems that can obtain results asynchronously
The development system is the opposite , The number of concurrent users cannot be controlled in an open system , Even if the business system can no longer handle redundant requests , New users will continue to come and make requests .
This is the case in most business systems .
Be careful : Please decide which test model to use according to the system business type . If the actual business type does not match the model tested , You can't achieve the desired effect .
Open model and closed model have opposite meanings , Do not mix in the same injection configuration .
Open model
Here is an example of an open model ( See resources for other languages 2):
setUp(
scn.injectOpen(
nothingFor(4), // Set a stop time , Within this time , Don't do anything?
atOnceUsers(10), // Inject the specified number of virtual users immediately
rampUsers(10).during(5), // Within a specified period of time , Gradually inject a specified number of virtual users
constantUsersPerSec(20).during(15), // Within a specified period of time , Inject a specified number of virtual users per second
constantUsersPerSec(20).during(15).randomized(), // Within a specified period of time , Inject randomly increasing or decreasing number of virtual users per second
rampUsersPerSec(10).to(20).during(10), // Within a specified period of time , The number of virtual users injected gradually increases from one value ( linear ) Increase to another value
rampUsersPerSec(10).to(20).during(10).randomized(), // Within a specified period of time , The number of injected virtual users increases from one value to another , But the growth process is not linear , It's a random jump
stressPeakUsers(1000).during(20) // Within a specified period of time , according to heaviside step The smooth approximation of the function is injected into a specified number of users
).protocols(httpProtocol)
);
Closed model
Here is an example of a closed model :
setUp(
scn.injectClosed(
constantConcurrentUsers(10).during(10), // Maintain a constant number of virtual users for a specified period of time
rampConcurrentUsers(10).to(20).during(10) // Within a specified period of time , The number of virtual users increases linearly from one value to another
)
);
Meta DSL
Before the test , Usually we don't know the throughput of the system . To test the bottleneck value , You may try to repeat the operation with different values , for example :
rampUsersPerSec(10).to(20).during(10),
rampUsersPerSec(20).to(30).during(10),
rampUsersPerSec(30).to(50).during(10),
rampUsersPerSec(50).to(70).during(10),
rampUsersPerSec(70).to(100).during(10),
);
To solve this problem ,Gatling stay 3.0 Added a kind of Meta DSL New methods to facilitate our operation .
incrementUsersPerSec(usersPerSecAddedByStage)
setUp(
// generate an open workload injection profile
// with levels of 10, 15, 20, 25 and 30 arriving users per second
// each level lasting 10 seconds
// separated by linear ramps lasting 10 seconds
scn.injectOpen(
incrementUsersPerSec(5.0)
.times(5)
.eachLevelLasting(10)
.separatedByRampsLasting(10)
.startingFrom(10) // Double
)
);
incrementConcurrentUsers(concurrentUsersAddedByStage)
setUp(
// generate a closed workload injection profile
// with levels of 10, 15, 20, 25 and 30 concurrent users
// each level lasting 10 seconds
// separated by linear ramps lasting 10 seconds
scn.injectClosed(
incrementConcurrentUsers(5)
.times(5)
.eachLevelLasting(10)
.separatedByRampsLasting(10)
.startingFrom(10) // Int
)
);
incrementUsersPerSec For open model load testing ,incrementConcurrentUsers Used for closed model load test .separatedByRampsLasting and startingFrom It's all optional .
If no slope is specified , Then the growth mode of virtual users is jumping . If the starting number of users is not specified , Will be taken from 0 Start .
Concurrent scenarios
In the same setUp You can set multiple scene injections at the same time , Then execute simultaneously
setUp(
scenario1.injectOpen(injectionProfile1),
scenario2.injectOpen(injectionProfile2)
);
Ordered scenes
Except for concurrent scenarios , Some scenes are orderly , Can pass andThen To set up an orderly scene . In an orderly scene , Only when the execution of the parent scenario is completed , The sub scenario starts to execute .
setUp(
parent.injectClosed(injectionProfile)
// child1 and child2 will start at the same time when last parent user will terminate
.andThen(
child1.injectClosed(injectionProfile)
// grandChild will start when last child1 user will terminate
.andThen(grandChild.injectClosed(injectionProfile)),
child2.injectClosed(injectionProfile)
)
);
Session
Session API
Session API User data can be processed programmatically .
Most of the time , There is one important point in load testing , That is to ensure that the request parameters of virtual users are different . If every virtual user uses the same parameters , That could be testing the cache , Instead of testing the actual system load .
Even worse , When you are in Java When a test case is executed on a virtual machine ,JVM Itself through the immediate compiler (JIT) Optimized the code , As a result, the performance results are different from those in the actual production environment .
Session
Session Is the status of the virtual user .
Generally speaking ,session It's a Map<String, Object> structure . stay Gatling in ,session All key value pairs in are Session attribute .
Gatling Medium scenario Is a workflow , Each step in the workflow is a Action,Session Data can be transferred in the workflow .
Set properties
// set one single attribute
Session newSession1 = session.set("key", "whateverValue");
// set multiple attributes
Session newSession2 = session.setAll(Collections.singletonMap("key", "value"));
// remove one single attribute
Session newSession3 = session.remove("key");
// remove multiple attributes
Session newSession4 = session.removeAll("key1", "key2");
// remove all non Gatling internal attributes
Session newSession5 = session.reset();
Session It's an immutable class , This means calling set After the method , Will return a new instance , Instead of the original instance .
// Incorrect usage : result from Session#set is discarded
exec(session -> {
session.set("foo", "bar");
System.out.println(session);
return session;
});
// Proper use
exec(session -> {
Session newSession = session.set("foo", "bar");
System.out.println(newSession);
return newSession;
});
from session Get user attributes in
// the unique id of this virtual user
long userId = session.userId();
// the name of the scenario this virtual user executes
String scenario = session.scenario();
// the groups this virtual user is currently in
List<String> groups = session.groups();
function
Use functions to generate dynamic parameters . As shown below :
// inline usage with a Java lamdba
exec(http("name")
.get(session -> "/foo/" + session.getString("param").toLowerCase(Locale.getDefault())));
// passing a reference to a function
Function<Session, String> f =
session -> "/foo/" + session.getString("param").toLowerCase(Locale.getDefault());
exec(http("name").get(f));
If you want to use randomly generated parameters , Must be generated in the function , Such as
.header("uuid", x -> RandomStringUtils.randomAlphanumeric(5)), It can't be used directly.header("uuid", RandomStringUtils.randomAlphanumeric(5)), So only the first request is a random value , Subsequent requests use the first generated value .
Feeders
stay gatling in , This can be done externally, for example csv file , Inject data into virtual users , You need to use Feeder.
Feeder It's actually an iterator Iterator<Map<String, T>> The nickname .
Here is a structure feeder Example :
// import org.apache.commons.lang3.RandomStringUtils
Iterator<Map<String, Object>> feeder =
Stream.generate((Supplier<Map<String, Object>>) () -> {
String email = RandomStringUtils.randomAlphanumeric(20) + "@foo.com";
return Collections.singletonMap("email", email);
}
).iterator();
External data source usage policy
There are many strategies for using external data sources :
// Default : Use iterators for base series
csv("foo").queue();
// Random selection of records in the sequence
csv("foo").random();
// Take records in the order after the disruption
csv("foo").shuffle();
// When the data ( From a to Z ) After that, I started from scratch
csv("foo").circular();
When using queue and shuffle strategy , Please make sure you have enough data , Once the data runs out ,gatling Will automatically shut down .
Use lists and arrays
Of course , You can also use in memory lists or arrays to inject data into virtual users :
// using an array
arrayFeeder(new Map[] {
Collections.singletonMap("foo", "foo1"),
Collections.singletonMap("foo", "foo2"),
Collections.singletonMap("foo", "foo3")
}).random();
// using a List
listFeeder(Arrays.asList(
Collections.singletonMap("foo", "foo1"),
Collections.singletonMap("foo", "foo2"),
Collections.singletonMap("foo", "foo3")
)).random();
file-based Feeders
The above mentioned strategy of fetching data during external data injection , Such as csv("foo").queue(). So this one csv Where should I put the files ?
When using build tools such as maven,gradle or sbt when , Documents must be placed in src/main/resourcese perhaps src/test/resources Under the table of contents .
Do not use relative paths for file paths
src/main/resources/data/file.csv, You should use the classpath :data/file.csv.
except csv The documents , also tsv/ssv/jsonFile/jsonUrl/jdbc/redis Import data in several ways , See resources for details Session->Feeders chapter .
Checks
Checks It can be used to verify the request results , And the returned result information can be extracted for reuse .
Checks Usually by calling... On the parent object check Method to implement , The following is a http Requested checks:
http("Gatling").get("https://gatling.io")
.check(status().is(200))
Of course , You can also define more than one at a time checks:
http("Gatling").get("https://gatling.io")
.check(
status().not(404),
status().not(500)
)
check API Provides a dedicated DSL, You can link the following operations :
- Definition check type
- extract
- transformation
- verification
- name
- preservation
Type of routine inspection
Here are some general inspection types , And by most gatling Supported by official agreements .
responseTimeInMillis
.check(responseTimeInMillis().lte(100)) // The response time is not greater than 100ms
bodyString
.check(
bodyString().is("{\"foo\": \"bar\"}"),
bodyString().is(ElFileBody("expected-template.json"))
)
bodyBytes
.check(
bodyBytes().is("{\"foo\": \"bar\"}".getBytes(StandardCharsets.UTF_8)),
bodyBytes().is(RawFileBody("expected.json"))
)
bodyLength
.check(bodyLength().is(1024))
bodyStream
Return the input stream of complete response body data bytes . In some cases , Use when you need to format the returned data before data processing .
.check(bodyStream().transform(is -> {
// take Base64 Format to String
try (InputStream base64Is = Base64.getDecoder().wrap(is)) {
return org.apache.commons.io.IOUtils.toString(base64Is, StandardCharsets.UTF_8.name());
} catch (IOException e) {
throw new RuntimeException("Impossible to decode Base64 stream");
}
}))
subString
This check returns the index position where the specified substring appears in the response text .
Usually used to check whether a substring exists , It's better than regular expressions CPU More efficient .
.check(
// with a static value
// (identical to substring("expected").find().exists())
substring("expected"),
// with a Gatling EL
substring("#{expectedKey}"),
// with a function
substring(session -> "expectedValue"),
substring("Error:").notExists(),
// this will save a List<Int>
substring("foo").findAll().saveAs("indices"),
// this will save the number of occurrences of foo
substring("foo").count().saveAs("counts")
)
regex
.check(
// with a static value without capture groups
regex("<td class=\"number\">"),
// with a Gatling EL without capture groups
regex("<td class=\"number\">ACC#{account_id}</td>"),
// with a static value with one single capture group
regex("/private/bank/account/(ACC[0-9]*)/operations.html")
)
stay Java15+,Scala and Kotlin in , You can use this transition string :“”“my “non-escaped” string”“”, There is no need for ’’
XPath
This check is for XML The response body takes effect
.check(
// simple expression for a document that doesn't use namespaces
xpath("//input[@id='text1']/@value"),
// mandatory namespaces parameter for a document that uses namespaces
xpath("//foo:input[@id='text1']/@value", Collections.singletonMap("foo", "http://foo.com"))
)
more Checks See resources for details Checks chapter .
extract
Extraction allows you to filter out the desired results , Then you can process the results in the following steps .
If the extraction operation is not explicitly defined ,Gatling Will be executed by default find.
find
find You can filter out individual elements . If the target appears more than once ,find Equate to find(0).
.check(
// The following two are equivalent . because jjmesPath Return only one value , therefore find It can be omitted
jmesPath("foo"),
jmesPath("foo").find(),
// jsonPath Multiple values may be returned
// The following three are equivalent , therefore find It can be omitted
jsonPath("$.foo"),
jsonPath("$.foo").find(),
jsonPath("$.foo").find(0),
// Capture the second occurrence of the element
jsonPath("$.foo").find(1)
)
findAll
It takes effect when there are multiple return values
.check(
jsonPath("$.foo").findAll()
)
findRandom
.check(
// identical to findRandom(1, false)
jsonPath("$.foo").findRandom(),
// identical to findRandom(1, false)
jsonPath("$.foo").findRandom(1),
// identical to findRandom(3, false)
// best effort to pick 3 entries, less if not enough
jsonPath("$.foo").findRandom(3),
// fail if less than 3 overall captured values
jsonPath("$.foo").findRandom(3, true)
)
count
.check(
jsonPath("$.foo").count()
)
transformation
Conversion is an optional step . After the extraction step above , We get the corresponding results , Before matching or saving the results , You may want to format the results , At this point, the transformation is needed .
withDefault
If in the previous step ( extract ) No value was obtained in , So you can go through withDefault Set the default value .
.check(
jsonPath("$.foo") // omitted find()
.withDefault("defaultValue")
)
transform
transform Is a function , This function is used to convert the extracted value , The result of the previous step must not be empty .
.check(
jsonPath("$.foo")
// append "bar" to the value captured in the previous step
.transform(string -> string + "bar")
)
transformWithSession
This step is actually transform A variation of , You can visit Session.
.check(
jsonPath("$.foo")
// append the value of the "bar" attribute
// to the value captured in the previous step
.transformWithSession((string, session) -> string + session.getString("bar"))
)
transformOption
And transfrom By contrast, , This operation can be executed even if no result is obtained in the previous step .
.check(
jmesPath("foo")
// extract can be null
.transform(extract -> Optional.of(extract).orElse("default"))
)
Of course , If your goal is just to set a default value , That's direct use
withDefaultIt might be more convenient .
transformOptionWithSession
.check(
jmesPath("foo")
// extract can be null
.transformWithSession((extract, session) ->
Optional.of(extract).orElse(session.getString("default"))
)
)
verification
Same as extraction , If not explicitly specified ,gatling Will be executed by default exists.
is and not
// is
.check(
// with a static value
jmesPath("foo").is("expected"),
// with a Gatling EL String (BEWARE DIFFERENT METHOD)
jmesPath("foo").isEL("#{expected}"),
// with a function
jmesPath("foo").is(session -> session.getString("expected"))
)
// not
.check(
// with a static value
jmesPath("foo").not("unexpected"),
// with a Gatling EL String (BEWARE DIFFERENT METHOD)
jmesPath("foo").notEL("#{unexpected}"),
// with a function
jmesPath("foo").not(session -> session.getString("unexpected"))
)
isNull and notNull
// isNull
.check(
jmesPath("foo")
.isNull()
)
// notNull
.check(
jmesPath("foo").notNull()
)
exists and notExists
.check(
jmesPath("foo").exists()
)
// not exists
.check(
jmesPath("foo").notExists()
)
in
.check(
// with a static values varargs
jmesPath("foo").in("value1", "value2"),
// with a static values List
jmesPath("foo").in(Arrays.asList("value1", "value2")),
// with a Gatling EL String that points to a List in Session (BEWARE DIFFERENT METHOD)
jmesPath("foo").inEL("#{expectedValues}"),
// with a function
jmesPath("foo").in(session -> Arrays.asList("value1", "value2"))
)
validate
.check(
jmesPath("foo")
.validate(
"MyCustomValidator",
(actual, session) -> {
String prefix = session.getString("prefix");
if (actual == null) {
throw new NullPointerException("Value is missing");
} else if (!actual.startsWith(prefix)) {
throw new IllegalArgumentException("Value " + actual + " should start with " + prefix);
}
return actual;
})
)
name
The naming is mainly to prevent mistakes , It can be displayed in the error message check The name of the .
.check(
jmesPath("foo").name("My custom error message")
)
preservation
Saving is also an optional operation , It is used to save the results extracted or transformed in the previous step to the virtual user Session in , For subsequent reuse .
saveAs
.check(
jmesPath("foo").saveAs("key")
)
Condition check
checkIf
// with a Gatling EL String condition that resolves a Boolean
.checkIf("#{bool}").then(
jmesPath("foo")
)
// with a function
.checkIf(session -> session.getString("key").equals("executeCheck")).then(
jmesPath("foo")
)
complete Check
All the above steps : Determine the type of inspection , extract , transformation , verification , preservation , All are Check Part of the workflow , Some steps are usually used in combination .
Here are some examples :
.check(
// check the HTTP status is 200
status().is(200),
// check the HTTP status is in [200, 210]
status().in(200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210),
// check the response body contains 5 https links
regex("https://(.*)").count().is(5),
// check the response body contains 2 https links,
// the first one to www.google.com and the second one to gatling.io
regex("https://(.*)/.*").findAll().is(Arrays.asList("www.google.com", "gatling.io")),
// check the response body contains a second occurrence of "someString"
substring("someString").find(1).exists(),
// check the response body does not contain "someString"
substring("someString").notExists()
)
HTTP
HTTP yes Gatling The main objectives of the agreement , So this is our main focus .
Gatling Allow you to web application , Load test services and websites . It almost supports HTTP and HTTPS All characteristics , Including the cache 、cookies And forwarding .
Here's a basic http Examples of load tests :
HttpProtocolBuilder httpProtocol = http.baseUrl("https://gatling.io");
ScenarioBuilder scn = scenario("Scenario"); // etc...
{
setUp(scn.injectOpen(atOnceUsers(1)).protocols(httpProtocol));
}
HTTP engine
warmUp
Java/NIO The engine starts and executes the first request with additional overhead , To counteract this effect ,Gatling Will automatically send to https://gatling.io. Send a request to warm up . Of course , You can change the preheating address , Or disable preheating .
// change warmUp Address
http.warmUp("https://www.google.com);
// Disable preheating
http.disableWarmUp();
maxConnectionsPerHost
To simulate a real browser ,gatling Multiple connections to the same host can be established for each virtual user at the same time . By default , The number of concurrent connections to the same remote host for the same virtual user ,gatling Limit it to 6. You can go through maxConnectionsPerHost To modify it .
http.maxConnectionsPerHost(10);
shareConnections
By default , Each virtual user has its own connection pool and SSLContext. This is actually a simulation web The scenario of browser accessing the server , Each virtual user is a browser .
And if you want to simulate a server to server scenario , under these circumstances , Per client ( Request originator ) There is a long-standing connection pool , It may be more appropriate for virtual users to share a global connection pool .
http.shareConnections();
enableHttp2
Can pass enableHttp2 Set to turn on HTTP2 Protocol support .
http.enableHttp2();
Be careful , To turn on HTTP2 function , Or use JDK9 Version above , Or make sure gatling In the configuration
gatling.http.ahc.useOpenSslNofalse.
Reference material
[1]. https://gatling.io/docs/gatling/tutorials/quickstart/
[2]. https://gatling.io/docs/gatling/reference/current/extensions/maven_plugin/
边栏推荐
- Source code analysis handler interview classic
- 2022年质量员-设备方向-岗位技能(质量员)复训题库及在线模拟考试
- CPU status information us, sy and other meanings
- 90%的项目经理都跳过的坑,你现在还在坑里吗?
- What is the difference between sap QM and UD for inspection lots with hum?
- 一键生成大学、专业甚至录取概率,AI填报志愿卡这么神奇?
- Kotlin keyword extension function
- Talk about GC of JVM
- Vim 常用快捷键
- kotlin 异步流
猜你喜欢

The research on the report "market insight into China's database security capabilities, 2022" was officially launched

**Unity中莫名其妙得小问题-灯光和天空盒

每日一题day8-515. 在每个树行中找最大值

Developer survey: rust/postgresql is the most popular, and PHP salary is low

如何在物联网低代码平台中进行任务管理?

How to avoid serious network security accidents?

In the era of knowledge economy, it will teach you to do well in knowledge management

不用Home Assistant,智汀也开源接入HomeKit、绿米设备?

Usage of multimeter

国内首款开源MySQL HTAP数据库即将发布,三大看点提前告知
随机推荐
How to avoid serious network security accidents?
CVPR 2022 | 美团技术团队精选论文解读
Ti Xing Shu'an joined the dragon lizard community to jointly create a network security ecosystem
One hour is worth seven days! Ingenuity in the work of programmers
2022年江西省安全员B证考试题库模拟考试平台操作
Resolve symbol conflicts for dynamic libraries
Kotlin composite suspend function
Troubleshooting the kubernetes problem: deleting the rancher's namespace by mistake causes the node to be emptied
一键生成大学、专业甚至录取概率,AI填报志愿卡这么神奇?
kotlin 继承、类、重载
What is the difference between sap QM and UD for inspection lots with hum?
2022年氟化工艺考试模拟100题及答案
3. Caller 服务调用 - dapr
Dragon lizard developer said: first time you got an electric shock, so you are such a dragon lizard community| Issue 8
钛星数安加入龙蜥社区,共同打造网络安全生态
kotlin 协程 lanch 详解
发扬连续作战优良作风 全力以赴确保北江大堤安全
居家办公更要高效-自动化办公完美提升摸鱼时间 | 社区征文
知识经济时代,教会你做好知识管理
首席信息安全官仍然会犯的漏洞管理错误