HashMap Ñ Ð½Ð°ÑÑÑойками и меÑод запÑÑка ÑимÑлÑÑии
import io.gatling.app.Gatling;
import org.testng.annotations.Test;
import scala.collection.mutable.HashMap;
public class DebugTest {
var config = new HashMap<String, String>();
void runSimulation(String simulationClass) {
config.put("gatling.core.simulationClass",
simulationClass);
Gatling.fromMap(config);
}
@Test void debugMaxPerfSimulation() {
runSimulation("simulation.MaxPerf");
}
}
@Test, запÑÑкаÑÑий ÑимÑлÑÑиÑ
import io.gatling.app.Gatling;
import org.testng.annotations.Test;
import scala.collection.mutable.HashMap;
public class DebugTest {
var config = new HashMap<String, String>();
void runSimulation(String simulationClass) {
config.put("gatling.core.simulationClass",
simulationClass);
Gatling.fromMap(config);
}
@Test void debugMaxPerfSimulation() {
runSimulation("simulation.MaxPerf");
}
}
СÑавим ÑоÑÐºÑ Ð¾ÑÑанова
и запÑÑкаем оÑÐ»Ð°Ð´ÐºÑ 
import io.gatling.app.Gatling;
import org.testng.annotations.Test;
import scala.collection.mutable.HashMap;
public class DebugTest {
var config = new HashMap<String, String>();
void runSimulation(String simulationClass) {
config.put("gatling.core.simulationClass",
simulationClass);
Gatling.fromMap(config);
}
@Test void debugMaxPerfSimulation() {
runSimulation("simulation.MaxPerf");
}
}
ÐапÑÑкаем ÑазнÑе ÑимÑлÑÑии ÑеÑез @Test
@Test void maxPerfSimulation() {
runSimulation("simulation.MaxPerf");
}
@Test void stableSimulation() {
runSimulation("simulation.Stable");
}
@Test void onceOnlySimulation() {
runSimulation("simulation.OnceOnly");
}
ÐенеÑиÑÑем html-оÑÑеÑÑ ÑеÑез @Test
@Test void generateReport() {
HashMap<String, String> configLocal = new HashMap<>();
{
configLocal.put("gatling.charting.maxPlotPerSeries",
"600");
configLocal.put("gatling.core.directory.reportsOnly",
"gatling/maxperfsimulation-20220321094726824");
}
Gatling.fromMap(configLocal);
}
JUnit Ñдобен Ð´Ð»Ñ Ð¾Ñладки, запÑÑка, ... Gatling Java-DSL
ÐÑладка Ð´Ð»Ñ gatling-scala-dsl
import io.gatling.app.Gatling
import io.gatling.core.ConfigKeys.{core, data}
object DebugApp extends App {
val config = scala.collection.mutable.Map(
core.SimulationClass -> "simulation.MaxPerf"
)
Gatling.fromMap(config)
}
СÑавим ÑоÑÐºÑ Ð¾ÑÑанова
и запÑÑкаем оÑÐ»Ð°Ð´ÐºÑ 
import io.gatling.app.Gatling
import io.gatling.core.ConfigKeys.{core, data}
object DebugApp extends App {
val config = scala.collection.mutable.Map(
core.SimulationClass -> "simulation.MaxPerf"
)
Gatling.fromMap(config)
}
ÐеÑколÑко ÑимÑлÑÑий в одном клаÑÑе c @Test
import io.gatling.app.Gatling
import io.gatling.core.ConfigKeys.{core, data}
import org.junit.Test
class DebugTest {
var config = scala.collection.mutable.Map()
@Test def maxPerfSimulation() {
config.put(core.SimulationClass, "simulation.MaxPerf")
Gatling.fromMap(config);
}
@Test def stableSimulation() {
config.put(core.SimulationClass, "simulation.Stable")
Gatling.fromMap(config);
}
}
JUnit Ñдобен Ð´Ð»Ñ Ð¾Ñладки, запÑÑка, ... Gatling Scala-DSL
3.
JMeter-Java-DSL и его оÑладка c @Test
-
ÐÑладка Ð´Ð»Ñ jmeter-java-dsl
-
ÐÑладка Ð´Ð»Ñ lambda-блоков
jsr223Sampler(v -> {...})
ÐÑладка Ð´Ð»Ñ jmeter-java-dsl (by desing)
public class ZeroTest {
@Test public void zero() throws IOException {
TestPlanStats stats = testPlan(
threadGroup(1, 1,
jsr223Sampler("zero", v -> {
v.log.info("Hello World!");
})
)
).run();
assertThat(stats.overall().sampleTimePercentile99())
.isLessThan(Duration.ofSeconds(5));
}
}
СÑавим ÑоÑÐºÑ Ð¾ÑÑанова
и запÑÑкаем оÑÐ»Ð°Ð´ÐºÑ 
public class ZeroTest {
@Test public void zero() throws IOException {
TestPlanStats stats = testPlan(
threadGroup(1, 1,
jsr223Sampler("zero", v -> {
v.log.info("Hello World!");
})
)
).run();
assertThat(stats.overall().sampleTimePercentile99())
.isLessThan(Duration.ofSeconds(5));
}
}
Lambda-вÑÑÐ°Ð¶ÐµÐ½Ð¸Ñ Ð¾ÑлаживаÑÑ Ð½ÐµÐ»ÑÐ·Ñ 
public class ZeroTest {
@Test public void zero() throws IOException {
TestPlanStats stats = testPlan(
threadGroup(1, 1,
jsr223Sampler("zero", v -> {
v.log.info("Hello World!");
})
)
).run();
assertThat(stats.overall().sampleTimePercentile99())
.isLessThan(Duration.ofSeconds(5));
}
}
Ðо можно ÑоздаÑÑ Ð²ÑпомогаÑелÑнÑе клаÑÑÑ 
СоздаÑÑ Ð² Ð½Ð¸Ñ ÐºÐ¾Ð½ÑÑÑÑкÑоÑÑ Ð¸ ÑÑÑлки на вÑе нÑжное
public class AbstractScenario {
public AbstractScenario AbstractScenario(
DslJsr223Sampler.SamplerVars v) {
this.samplerVars = v;
return this.setLog(v.log)
.setCtx(v.ctx)
.setVars(v.vars)
.setProps(v.props)
.setSampleResult(v.sampleResult);
}
...
}
РпиÑаÑÑ Ð¼ÐµÑÐ¾Ð´Ñ ÐºÐ»Ð°ÑÑов
public class SomeScenario extends AbstractScenario {
int errorCount = 0;
public boolean helloWorld() {
this.log.info("Hello World!");
}
}
Ðегко оÑлаживаемÑе меÑÐ¾Ð´Ñ ÐºÐ»Ð°ÑÑов
public class SomeScenario extends AbstractScenario {
int errorCount = 0;
public boolean helloWorld() {
this.log.info("Hello World!");
}
}
ÐоÑоÑÑе вÑзÑваÑÑ Ð² lambda-вÑÑажениÑÑ
public class SomeScenario extends AbstractScenario {
int errorCount = 0;
public boolean helloWorld() {
this.log.info("Hello World!");
}
}
public class ZeroTest {
@Test public void zero() throws IOException {
TestPlanStats stats = testPlan(
threadGroup(1, 1,
jsr223Sampler("zero", v -> {
new SomeScenario(v).helloWorld();
}))).run();
}
}
JUnit Ñдобен Ð´Ð»Ñ Ð¾Ñладки, запÑÑка, ... JMeter Java-DSL
TestId/RunId/*Id или Start+StopTime Ð´Ð»Ñ ÑÑÐ°Ð²Ð½ÐµÐ½Ð¸Ñ ÑеÑÑов
4.
Start/Stop-time и иÑ
ÑикÑаÑÐ¸Ñ Ð¿Ñи оÑладке
-
Grafana и ÑÑавнение меÑÑик из Prometheus, Victoria, InfluxDB
-
Jenkins и ÑикÑаÑÐ¸Ñ Ð¼Ð¾Ð¼ÐµÐ½Ñов ÑÑаÑÑа и завеÑÑÐµÐ½Ð¸Ñ ÑеÑÑа
-
JUnit Ð´Ð»Ñ ÑикÑаÑии Start/Stop-time пÑи оÑладке
Grafana и ÑÑавнение меÑÑик Prometheus, InfluxDB, ...
Grafana и ÑÑавнение меÑÑик Prometheus, InfluxDB, ...
1. ÐÑобÑазиÑÑ ÑаблиÑÑ Ð¿Ð¾ пеÑÐ²Ð¾Ð¼Ñ ÑеÑÑÑ:
- "Start" и "Stop", Ñип "tag"/"label", ÑоÑÐ¼Ð°Ñ unixTimeStamp
2. ÐÑи клике по ÑÑÑоке пеÑвой ÑаблиÑÑ ÑоÑ
ÑанÑем в URL:
- from=Start, to=Stop, Start1=Start
3. ÐÑобÑазиÑÑ ÑаблиÑÑ Ð¿Ð¾ вÑоÑÐ¾Ð¼Ñ ÑеÑÑÑ
- "Start" и "Stop", Ñип "tag"/"label", ÑоÑÐ¼Ð°Ñ unixTimeStamp
- Start1 - дополниÑелÑÐ½Ð°Ñ ÐºÐ¾Ð»Ð¾Ð½ÐºÐ° из пеÑеменной Start1
- Offset - вÑÑиÑлÑÐµÐ¼Ð°Ñ ÐºÐ¾Ð»Ð¾Ð½ÐºÐ° Start1-Start
4. ÐÑи клике по ÑÑÑоке вÑоÑой ÑаблиÑÑ ÑоÑ
ÑанÑем в URL:
- Offset=Offset
5. ÐÑобÑазиÑÑ Ð¼ÐµÑÑики по пеÑÐ²Ð¾Ð¼Ñ Ð¸ вÑоÑÐ¾Ð¼Ñ ÑеÑÑам
- по пеÑÐ²Ð¾Ð¼Ñ Ð¿ÑоÑÑо Ð¾Ñ from до to
- по вÑоÑÐ¾Ð¼Ñ Ñо ÑмеÑением Offset
Ðак ÑÐ¾Ñ ÑаниÑÑ Start/Stop-time Ð´Ð»Ñ ÐºÐ°Ð¾Ð¶Ð´Ð¾Ð³Ð¾ запÑÑка ÑеÑÑа?
Jenkins и ÑикÑаÑÐ¸Ñ Ð¼Ð¾Ð¼ÐµÐ½Ñов ÑÑаÑÑа и завеÑÑениÑ
Ðо ÑеÑÑа: ÑÐ¾Ñ ÑаниÑÑ Start и ÑаÑÑÑÑнÑй Stop-time
- как tag/label + дополниÑелÑнÑе Ñеги
ТеÑÑ: ab, curl+bash, k6, jmeter, locust, gatling, junit, ...
- лÑбой ÑеÑÑ!
ÐоÑле ÑеÑÑа: ÑÐ¾Ñ ÑаниÑÑ Start и Stop-time ÑакÑиÑеÑкие
- как tag/label + дополниÑелÑнÑе Ñеги
ÐÑÐ¸Ð¼ÐµÑ Ð·Ð°Ð¿Ð¸Ñи меÑÑик в ÑоÑмаÑе InfluxLine в VM
metricTime = 1640980800 # Fri Dec 31 2021 20:00:00 GMT+0000
reqBody = f'testStats,' \
f'suite={row["suite"]},' \
f'environment={row["env"]},' \
f'version={row["version"]},' \
f'start={row["startUnix"]},' \
f'stop={row["stopUnix"]} ' \
f'duration={row["duration"]} {metricTime}000000000'
http.post(
url="http://victoriaMetrics:8428/write",
data=reqBody
)
@BeforeAll, @AfterAll из JUnit 5
@BeforeClass, @AfterClass из JUnit 4
@BeforeClass public static void storeStartStopTimeBeforeTest() {
var suite = "debug-max-perf";
var version = "1.111111";
long start = Instant.now().getEpochSecond();
long duration = 60 * 60 * 1000; // 1 hour
long stop = start + duration;
var metricTime = "1640980800" + "000000000";
var reqBody = String.format("testStats," +
"suite=%s,environment=%s,version=%s," +
"start=%d,stop=%d duration=%d %s",
suite, env, version, start, stop,
duration, metricTime); ...
}
Ðожно не ÑÐ¾Ñ ÑанÑÑÑ duration
// testStats_duration:
var reqBody = String.format("testStats," +
"suite=%s,environment=%s,version=%s," +
"start=%d,stop=%d duration=%d %s",
suite, env, version, startUnix, stopUnix, duration, metricTime);
// testStats_stop:
var reqBody = String.format("testStats," +
"suite=%s,environment=%s,version=%s," +
"start=%d stop=%d %s",
suite, env, version, startUnix, stopUnix, metricTime);
Ðлавное -- ÑÐ¾Ñ ÑаниÑÑ start и stop
JUnit Ñдобен Ð´Ð»Ñ ÑикÑаÑии Start/Stop-time пÑи оÑладке без CI
5.
TestId/RunId/*Id и его генеÑаÑÐ¸Ñ Ð¿Ñи оÑладке
-
InfluxDB или Prometheus Ð´Ð»Ñ Ð°Ð³Ð³ÑегаÑии ÑезÑлÑÑаÑов ÑеÑÑа
-
Jenkins и ÑезÑлÑÑаÑÑ Ð¾ÑделÑного ÑеÑÑа
-
JUnit Ð´Ð»Ñ Ð³ÐµÐ½ÐµÑаÑии TestId/RunId/*Id пÑи оÑладке
ХоÑеÑÑÑ Ð°Ð³Ð³ÑегиÑоваÑÑ Ð¼ÐµÑÑики по ÑеÑÑÑ
УдобнÑй клÑÑ Ð³ÑÑппиÑовки -- BUILD_ID
ÐмиÑаÑÐ¸Ñ BUILD_ID Ð´Ð»Ñ ÑеÑÑов Ñ @BeforeEach
static String BUILD_ID;
@BeforeEach public void beforeEach()
{
BUILD_ID = Instant.now().toString().replace(":", "-");
}
@Test public void test() throws IOException {
TestPlanStats stats = testPlan(
threadGroup(1, 1, jsr223Sampler("test", v -> {
v.log.info("Hello World!"); })
),
influxDbListener("http://influxdb:8086/write?db=jmeter")
.tag("BUILD_ID", BUILD_ID),
).run();
}
JUnit Ñдобен Ð´Ð»Ñ ÑмÑлÑÑии TestId/RunId/*Id пÑи оÑладке без CI
ÐаÑамеÑÑÑ ÑеÑÑа как код
ÐÑоводил ÑеÑÐ¸Ñ ÑеÑÑов Ñ ÑазнÑм ÑоÑÑом нагÑÑзки
6.
@ParameterizedTest или паÑамеÑÑÑ ÐºÐ°Ðº код
@ParameterizedTest
@CsvSource({
"slow, 100, 10",
"medium, 100, 5",
"fast, 100, 2",
"ultra, 100, 1",
"wow, 100, 0"
})
public void loadTest(String testName,
int threads,
int rampDurationMinutes)
throws IOException, InterruptedException, TimeoutException {
...
}
СÑÑпени ÑÐ»Ð¾Ð¶Ð½Ñ Ð² анализе, ÑÑебÑÑÑ Ð¸Ð½Ð¶ÐµÐ½ÐµÑа
ТеÑÑÑ-ÑÑÑпени пÑоÑÑÑ Ð² анализе
Assertion на каждÑÑ ÑÑÑÐ¿ÐµÐ½Ñ Ð¼Ð¾Ð¶Ð½Ð¾ задаÑÑ ÐºÐ¾Ð´Ð¾Ð¼
@ParameterizedTest
@CsvSource({
"100",
"200",
"300",
"400",
})
public void loadTest(int threads) {
TestPlanStats stats = testPlan( ... ).run();
assertThat(stats.overall().sampleTimePercentile99()).
isLessThan(Duration.ofSeconds(30));
}
JUnit Ñдобен Ð´Ð»Ñ Ð¿ÑоÑÑÑÑ Ð² анализе ÑеÑÑов Ñ Ð¿Ð°ÑамеÑÑами
ÐадежнÑе и пÑоÑÑÑе ÑеÑÑÑ Ð½Ð° ÑÐ¸ÐºÐ»Ð°Ñ Ð¸ поÑокаÑ
7.
@RepeatedTest Ð´Ð»Ñ ÑеÑÑов маÑÑÑабиÑÑемоÑÑи
@Execution(ExecutionMode.SAME_THREAD)
public class ALotOfLiteMember {
static LinkedBlockingQueue<HazelcastInstance> queueHz =
new LinkedBlockingQueue<>();
static LinkedBlockingQueue<Integer> queueStop =
new LinkedBlockingQueue<>();
@RepeatedTest(40) public void ConnectToHazelcast()
throws InterruptedException {
var config = new ConfigBuilder().buildConfig();
var hazelcastInstance =
Hazelcast.newHazelcastInstance(config);
queueHz.put(hazelcastInstance);
queueStop.poll(30, TimeUnit.SECONDS);
}
}
40 иÑеÑаÑий Ñ Ð¿Ð°Ñзами по 30 ÑекÑнд Ð¼ÐµÐ¶Ð´Ñ Ð½Ð¸Ð¼Ð¸
@Execution(ExecutionMode.SAME_THREAD)
public class ALotOfLiteMember {
static LinkedBlockingQueue<HazelcastInstance> queueHz =
new LinkedBlockingQueue<>();
static LinkedBlockingQueue<Integer> queueStop =
new LinkedBlockingQueue<>();
@RepeatedTest(40) public void ConnectToHazelcast()
throws InterruptedException {
var config = new ConfigBuilder().buildConfig();
var hazelcastInstance =
Hazelcast.newHazelcastInstance(config);
queueHz.put(hazelcastInstance);
queueStop.poll(30, TimeUnit.SECONDS);
}
}
8.
@Execution(ExecutionMode.CONCURRENT)
@Execution(ExecutionMode.CONCURRENT)
public class ClusterBench {
static Cluster cluster = new ClusterImpl();
@RepeatedTest(30)
public void getOptionalParam() {
int loop = 10000 * 2;
for (int i = 0; i < loop; i++) {
cluster.getOptionalParam(i);
} } }
Ðожно ÑеÑÑиÑоваÑÑ Ð² неÑколÑко поÑоков
JUnit Ñдобен Ð´Ð»Ñ Ð¿ÑоÑÑÑÑ ÑеÑÑов Ñ Ð¸ÑеÑаÑиÑми и паÑзами
ÐаÑни Ñвой Ð´ÐµÐ½Ñ Ñ ÐºÐ¾Ñе
ÐаÑни Ñвой ÑеÑÑ Ñ JUnit !
JUnit Ð´Ð»Ñ Ð½Ð°Ð³ÑÑзки: «ÐаÑни Ñвой ÑеÑÑ Ñ JUnit!»
Чем JUnit полезен нагÑÑзоÑникÑ
Gatling и его оÑладка c @Test
JMeter-Java-DSL и его оÑладка c @Test
Start/Stop-time и Ð¸Ñ ÑикÑаÑÐ¸Ñ Ð¿Ñи оÑладке
TestId/RunId/*Id и его генеÑаÑÐ¸Ñ Ð¿Ñи оÑладке
@ParameterizedTest или паÑамеÑÑÑ ÐºÐ°Ðº код
@RepeatedTest Ð´Ð»Ñ ÑеÑÑов маÑÑÑабиÑÑемоÑÑи
@Execution(ExecutionMode.CONCURRENT) Ð´Ð»Ñ Ð¼Ð½Ð¾Ð³Ð¾Ð¿Ð¾ÑоÑноÑÑи
СмиÑнов ÐÑÑеÑлав |
Miro,
qa_load,
smirnovqa
polarnik.github.io/junit-for-load-testing/
ÐовÑÑÐ°Ñ ÐºÐ°ÑеÑÑво более деÑÑÑи леÑ. ÐанимаÑÑÑ ÑиÑÑемой диÑÑанÑионного банковÑкого обÑлÑÐ¶Ð¸Ð²Ð°Ð½Ð¸Ñ ÑÑидиÑеÑÐºÐ¸Ñ Ð»Ð¸Ñ. ÐÑновной пÑоÑÐ¸Ð»Ñ Ð¼Ð¾ÐµÐ¹ ÑабоÑÑ â ÑеÑÑиÑование пÑоизводиÑелÑноÑÑи. Ð Ð°Ð·Ð²Ð¸Ð²Ð°Ñ ÑообÑеÑÑво инженеÑов по ÑеÑÑиÑÐ¾Ð²Ð°Ð½Ð¸Ñ Ð¿ÑоизводиÑелÑноÑÑи, Ð¿Ð¾Ð¼Ð¾Ð³Ð°Ñ ÐºÐ¾Ð»Ð»ÐµÐ³Ð°Ð¼ в telegram ÑаÑе «QA â Load & Performance».
