From qa-load-testing
Authors Apache JMeter `.jmx` test plans (Thread Groups + HTTP samplers + assertions + listeners) in the JMeter GUI, runs them headlessly via `jmeter -n -t plan.jmx -l results.jtl`, generates an HTML dashboard with `-e -o`, and gates CI on JTL parsing. Use when the project has an existing JMeter investment, needs JVM-native load tooling, or works in domains with strong JMeter community support (banking, telecom, enterprise).
How this skill is triggered — by the user, by Claude, or both
Slash command
/qa-load-testing:jmeter-load-testingThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
Apache JMeter is the long-running JVM-native load-testing tool. Tests
Apache JMeter is the long-running JVM-native load-testing tool. Tests
are XML .jmx files authored in JMeter's GUI; CI runs them headless
via the jmeter CLI (jmeter-getstarted).
The official guidance is explicit:
"GUI mode should only be used for creating the test script, CLI mode (NON GUI) must be used for load testing." (jmeter-getstarted)
This skill covers the CLI / CI side. Authoring is GUI-driven and out of scope here - see the JMeter user manual for the Thread Group / HTTP Sampler / Assertion authoring flow.
.jmx test plans.If the team is starting fresh, evaluate
k6-load-testing (developer-friendly
JS), gatling-load-testing (JVM
DSL), or locust-load-testing
(Python) before adopting JMeter - XML authoring has a steep learning
curve.
JMeter requires Java 8 or higher with JAVA_HOME set. Download
the latest release from
jmeter.apache.org and extract - there
is no installer (jmeter-getstarted).
For Docker-based CI, official images are at apache/jmeter. Pin to
a specific tag rather than latest.
Per jmeter-getstarted:
jmeter -n -t test.jmx -l results.jtl
| Flag | Purpose |
|---|---|
-n | Non-GUI mode. Required for load tests. |
-t | Path to the .jmx test plan. |
-l | Output file for raw sample results (JTL - CSV-shaped). |
Per jmeter-getstarted:
jmeter -n -t test.jmx -l results.jtl -e -o report_folder
| Flag | Purpose |
|---|---|
-e | Generate the HTML dashboard report automatically. |
-o | Output folder (must be empty or non-existent). |
The dashboard shows percentiles, throughput, error rates, response- time graphs, and per-sampler breakdowns - the canonical JMeter output for human review.
| Flag | Purpose |
|---|---|
-J<property>=<value> | Override a JMeter property at the JVM level. |
-G<property>=<value> | Override a property in distributed (remote) mode. |
-Jjmeter.save.saveservice.output_format=csv | Force CSV JTL (vs. XML). |
-q <props-file> | Additional properties file. |
-r | Start the test on remote slaves (distributed mode). |
-X | Exit JMeter when the test finishes. |
For multi-environment runs, parameterize the test plan with
${__P(api.base.url, default)} and override at the CLI:
jmeter -n -t orders.jmx -l results.jtl \
-Japi.base.url=https://staging.example.com \
-Japi.token=$API_TOKEN
The JTL file is the structured artifact for CI gating. Default JTL
columns (CSV): timeStamp, elapsed, label, responseCode,
responseMessage, threadName, dataType, success, failureMessage,
bytes, sentBytes, grpThreads, allThreads, URL, Latency,
IdleTime, Connect.
Quick-and-dirty pass/fail with awk:
# Count errors
awk -F',' 'NR>1 && $8=="false"' results.jtl | wc -l
# Compute mean response time
awk -F',' 'NR>1 { sum+=$2; n++ } END { print sum/n }' results.jtl
For richer parsing, use the JMeter HTML report's
statistics.json under the report folder - it contains the
percentiles per sampler in JSON form.
# .github/workflows/jmeter.yml
name: load-test
on:
pull_request:
paths: ['tests/load/**.jmx']
schedule:
- cron: '0 4 * * *'
jobs:
jmeter:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- name: Run JMeter via Docker
env:
API_TOKEN: ${{ secrets.STAGING_API_TOKEN }}
run: |
docker run --rm \
-v "$PWD:/work" \
-w /work \
apache/jmeter \
-n -t tests/load/orders.jmx \
-l results.jtl \
-e -o report \
-Japi.token=$API_TOKEN \
-Japi.base.url=https://staging.example.com
- name: Pass/fail gate
run: |
ERRORS=$(awk -F',' 'NR>1 && $8=="false"' results.jtl | wc -l)
if [ "$ERRORS" -gt 10 ]; then
echo "::error::Got $ERRORS errors (>10 threshold)"
exit 1
fi
- name: Upload report
if: always()
uses: actions/upload-artifact@v4
with:
name: jmeter-report
path: |
report/
results.jtl
retention-days: 14
The Docker invocation pattern keeps the CI runner clean - no Java / JMeter install on the runner.
| Anti-pattern | Why it fails | Fix |
|---|---|---|
| Running tests in GUI mode "just for this one quick run" | GUI runner adds overhead; metrics are skewed; per jmeter-getstarted this is explicitly forbidden for load tests. | Always -n. GUI is for authoring only. |
Hard-coding URLs / tokens in the .jmx XML | Test plan binds to one environment. | Parameterize: ${__P(api.base.url, ...)}; override with -J. |
| Saving JTL in XML format | XML JTL files are 5-10x larger than CSV; slow to parse. | Force CSV with -Jjmeter.save.saveservice.output_format=csv. |
| Listeners enabled in CI runs | UI listeners (View Results Tree, Aggregate Report) consume RAM proportional to sample count; OOMs at scale. | Disable all listeners in .jmx; emit JTL only; generate HTML report post-run via -e -o. |
| One mega-test-plan with 100 samplers | Failure attribution is hard; runtime dominated by one slow endpoint. | Split into per-domain .jmx files; run as separate CI jobs. |
| Threshold gates only on error rate | A 30-second response that succeeds passes the rate gate but breaks UX. | Pair error-rate with percentile gates parsed from statistics.json. |
.jmx files are not human-friendly; reviews of
test-plan changes are awkward.k6-load-testing,
gatling-load-testing,
locust-load-testing -
alternatives by stack.perf-budget-gate - downstream
gate aggregating multiple runner verdicts.npx claudepluginhub testland/qa --plugin qa-load-testingProvides CDSS development patterns for drug interaction checking, dose validation, clinical scoring (NEWS2, qSOFA), and alert classification integrated into EMR workflows.