DEV Community

Cover image for TestFly Part 9: In-process load testing in Java with Gatling and K6
Hakan GÜL
Hakan GÜL

Posted on Originally published at hakangul.lovable.app

TestFly Part 9: In-process load testing in Java with Gatling and K6

TestFly 1.1.0 adds built-in load and performance testing, powered by Gatling and lightweight virtual threads. You can write, parameterize and run high-concurrency load scenarios inside ordinary TestNG or JUnit 5 test classes, without switching to an external tool.

Why keep functional and load tests together

Performance testing often comes last in the development cycle, or it lives in a separate toolchain such as the JMeter GUI or standalone scripts. That split causes a few problems:

  • Test data and authentication setup get duplicated between the functional and performance repos.
  • Performance tests run rarely, often right before a production release.
  • CI/CD quality gates are hard to configure when the tests run on different runners.

In TestFly you declare load simulations with the same test classes, base configuration (testfly.yml) and assertions you already use for WebUI and API automation.

How load testing works in TestFly

There are two ways to write a load test.

1. Declarative mode with @LoadTest

Add @LoadTest to a test method to set the number of concurrent virtual users and the ramp-up phase:

package io.testfly.examples.loadtest;

import io.testfly.loadtest.LoadTest;
import io.testfly.test.BaseTest;
import org.testng.annotations.Test;

public class SimpleLoadTest extends BaseTest {

    @Test
    @LoadTest(users = 100, rampUpSeconds = 15, durationSeconds = 60)
    public void testCheckoutUnderSurgeTraffic() {
        apiClient().post("/api/checkout")
            .body("{\"cartId\": 1024}")
            .send()
            .assertStatus(200);
    }
}
Enter fullscreen mode Exit fullscreen mode

2. Fluent programmatic DSL with load()

For multi-step user journeys and dynamic feeders, use the fluent LoadScenario DSL:

package io.testfly.examples.loadtest;

import io.testfly.loadtest.LoadScenario;
import io.testfly.loadtest.LoadTestFeeder;
import io.testfly.test.BaseTest;
import org.testng.annotations.Test;

public class AdvancedLoadJourneyTest extends BaseTest {

    @Test
    public void simulateUserBrowsingJourney() {
        LoadTestFeeder users = LoadTestFeeder.csv("testdata/users.csv");

        LoadScenario.scenario("Search and Add to Cart")
            .feed(users)
            .step("Browse Catalog", client -> client.get("/products?q=shoes").send().assertStatus(200))
            .pause(1000)
            .step("Add to Cart", client -> client.post("/cart/items").body("{\"id\": 42}").send().assertStatus(201))
            .users(500)
            .rampUp(20)
            .run();
    }
}
Enter fullscreen mode Exit fullscreen mode

Checking performance SLOs in code

Metrics only help if something checks them automatically. TestFly records the timing of every request with millisecond precision and computes the standard percentiles (P50, P90, P95, P99):

Percentile Metric Meaning Typical SLO Target
P50 (Median) 50% of requests completed faster than this time < 150 ms
P90 90% of requests completed faster than this time < 350 ms
P95 95% of requests completed faster than this time < 500 ms
P99 Tail latency affecting 1% of users < 1200 ms

Write your service-level objectives as assertions and the build fails on its own when performance regresses:

import static io.testfly.loadtest.LoadTestAssert.*;

assertP95Below(Duration.ofMillis(450));
assertErrorRateBelow(0.01); // Less than 1% failures
Enter fullscreen mode Exit fullscreen mode

Reporting

TestFly produces an interactive HTML performance report with:

  • live latency distribution curves and percentile breakdowns
  • HTTP status code distributions (2xx, 4xx, 5xx)
  • direct export to Allure Reports and ReportPortal, so load results show up in the same dashboards as the rest of your tests

FAQ

Does TestFly require JMeter or an external binary?

No. Simulations run in-process on Gatling's engine or on native Java virtual threads, so there is no external runtime binary to install.

Can I run load tests in CI/CD without overwhelming local machines?

Yes. Load tests run headless in CI (GitHub Actions, Bitbucket, Jenkins). For very large loads (100k+ RPS) you can schedule containerized runner pods on Kubernetes.

Can I use API authentication tokens in load tests?

Yes. TestFly's ApiClient passes Bearer tokens and session headers to the load test steps.


Originally published on hakangul.lovable.app.

Top comments (0)