当前位置:网站首页>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/
边栏推荐
- Use of kotlin arrays, collections, and maps
- kotlin 组合挂起函数
- Kotlin coroutine context and scheduler
- npm包【详解】(内含npm包的开发、发布、安装、更新、搜索、卸载、查看、版本号更新规则、package.json详解等)
- Why did the audio and video based cloud conference usher in a big explosion of development?
- kotlin 语言特性
- MySQL interview questions
- 每日一题day8-515. 在每个树行中找最大值
- Docker安装redis
- [5g NR] 5g NR system architecture
猜你喜欢

黄金年代入场券之《Web3.0安全手册》

数据科学家面临的七大挑战及解决方法

首席信息安全官仍然会犯的漏洞管理错误

常识知识点

万用表的使用方法

Eight major trends in the industrial Internet of things (iiot)

2022年质量员-设备方向-岗位技能(质量员)复训题库及在线模拟考试

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

hands-on-data-analysis 第三单元 模型搭建和评估

居家办公更要高效-自动化办公完美提升摸鱼时间 | 社区征文
随机推荐
Golden age ticket: Web3.0 Security Manual
Goldfish rhca memoirs: do447 manage lists and credentials -- create machine credentials for the access list host
Resolve symbol conflicts for dynamic libraries
[one picture series] one picture to understand Tencent Qianfan ipaas
Kotlin interface generic covariant inversion
Daily question 8-515 Find the maximum value in each tree row
System status identifier 'hum' for SAP QM inspection lot
黄金年代入场券之《Web3.0安全手册》
The hidden corner of codefarming: five things that developers hate most
One hour is worth seven days! Ingenuity in the work of programmers
Kotlin keyword extension function
知识经济时代,教会你做好知识管理
Vim 常用快捷键
redis 数据类型详解
39 - read XML node and attribute values
Goldfish rhca memoirs: do447 managing projects and conducting operations -- creating a project for ansible scripts
源碼解析 Handler 面試寶典
CPU process priority
Memory introduction
**Unity中莫名其妙得小问题-灯光和天空盒