API测试
- 作者仓库星标 136
- 许可证 MIT
- 作者更新于 实时读取
- 作者仓库 qaskills
- 领域
- 工程开发 · jmeter · load-testing · performance
- 兼容 Agent
-
- Claude Code
- Cursor
- Windsurf
- Codex
- Aider
- Continue
- +1
- 信任分
- 100 / 100 · 已通过审计
- 作者 / 版本 / 许可
- @PramodDutta · v1.0.0 · MIT
- Token 消耗评级
- 中等消耗
- 接入复杂程度
- 需简单配置
- 是否需要外部 API Key
- 不需要
- 兼容的系统
- 未声明(默认跨平台)
- 底层运行要求
- 无特殊要求
- 文件与系统权限
-
- 只读
- 允许写入 / 修改
- Shell 执行
- 网络行为
- 允许外网请求
- 安装命令数
- 7 条
档案由构建时根据 SKILL.md 与安装命令自动衍生,可能与作者实际意图存在差异。
---
name: JMeter Load Testing
description: Load and performance testing skill using Apache JMeter, covering test plans, thread groups, asse…
category: 工程开发
runtime: 无特殊运行时
---
# JMeter Load Testing 输出预览
## PART A: 任务判断
- 适用问题:代码实现、重构、调试或代码审查。
- 输入要求:目标材料、限制条件、期望输出和验收方式。
- 证据边界:围绕“Core Principles / Project Structure / Test Plan Structure”读取原文规则,不把推断写成作者承诺。
## PART B: 执行结果
- **01** 任务判断:确认你的需求是否属于代码实现、重构、调试或代码审查,并标出输入、限制和预期结果。
- **02** 执行计划:优先按“Core Principles / Project Structure / Test Plan Structure”拆成步骤,说明每一步会读取什么、修改什么、产出什么。
- **03** 交付结果:给出可复制的命令、文件改动、检查清单或内容草稿,并说明如何继续迭代。
- **04** 风险边界:结合 读取文件、写入/修改文件、执行终端命令、会按任务需要访问外部网络、通常不需要额外 API Key 给出执行前确认项。
## Running Rules
- 读取文件、写入/修改文件、执行终端命令;会按任务需要访问外部网络;通常不需要额外 API Key。
- 先小样例验证,再放大到真实任务。
- 交付时同时给结果、检查口径和下一步迭代建议。 原文出现了 `/login`、`/auth`、`/products`、`/cart`、`/checkout` 这类斜杠命令;如果你的 Agent 支持命令触发,优先用命令开场,再补充目标和边界。
告诉 Agent 目标文件或材料、期望结果、不可改范围、是否允许联网或执行命令。本 Skill 的权限画像是:读取文件、写入/修改文件、执行终端命令。
先用一个小任务确认它会围绕“Core Principles / Project Structure / Test Plan Structure”工作;涉及文件或命令时,先看 diff、日志、预览或测试结果。
检查最终产物是否包含明确结果、必要证据和下一步动作;如果输出泛泛而谈,就补充输入、边界和验收标准后重跑。
---
name: JMeter Load Testing
description: Load and performance testing skill using Apache JMeter, covering test plans, thread groups, asse…
category: 工程开发
source: PramodDutta/qaskills
---
# JMeter Load Testing
## 什么时候使用
- JMeter Load Testing 是一个工程开发方向的技能,扩展 Agent 在写代码、做 review、跑测试这类场景下的能力 适合处理工程开发场景下的代码实现、调试、重构、测试或代码审查,核心价值是把输入、判断、执行、验证和交…
- 面向代码实现、重构、调试或代码审查,优先处理能明确输入、步骤和验收标准的工作。
## 需要提供什么
- 目标材料、目录范围、期望结果和不可改动内容。
- 是否允许联网、执行命令、读写文件或调用外部服务。
## 执行规则
- 围绕「Core Principles / Project Structure / Test Plan Structure」组织步骤,不把推断写成作者事实。
- 读取文件、写入/修改文件、执行终端命令;会按任务需要访问外部网络;通常不需要额外 API Key。
- 先跑小样例,确认结果可检查后再扩大任务范围。
## 输出要求
- 给出最终产物、关键证据、验证方式和下一步动作。
- 信息不足时标记 unknown,不编造命令、平台或依赖。 作者原文负责流程事实;仓库文件负责来源和命令;流狐只补充适用场景、限制和质量判断。
skill "JMeter Load Testing" {
输入层 -> 用户目标 + 目标文件 + 禁止范围 + 验收标准
上下文层 -> Core Principles / Project Structure / Test Plan Structure
规则层 -> SKILL.md 触发条件 / 执行顺序 / 输出格式
运行层 -> 无特殊运行时 | 读取文件、写入/修改文件、执行终端命令 | 会按任务需要访问外部网络
安全层 -> 通常不需要额外 API Key + 小任务验证 + diff / 日志复核
输出层 -> 可复制结果 + 检查清单 + 下一步迭代
} JMeter Load Testing Skill
You are an expert performance engineer specializing in Apache JMeter. When the user asks you to create, review, or debug JMeter test plans, follow these detailed instructions.
Core Principles
- Realistic load modeling -- Thread groups must simulate real user behavior with think times.
- Correlation -- Extract dynamic values (session IDs, tokens) from responses and reuse them.
- Parameterization -- Use CSV Data Set Config for test data; never hardcode user-specific values.
- Assertions everywhere -- Every sampler should have at least one assertion to verify correctness.
- Non-GUI execution -- Always run actual load tests from the command line, never the GUI.
Project Structure
jmeter/
test-plans/
smoke-test.jmx
load-test.jmx
stress-test.jmx
api-test.jmx
data/
users.csv
products.csv
payloads/
create-order.json
lib/
custom-plugins.jar
scripts/
run-load-test.sh
generate-report.sh
results/
.gitkeep
reports/
.gitkeep
jmeter.properties
Test Plan Structure
A well-organized JMeter test plan follows this hierarchy:
Test Plan
├── User Defined Variables
├── HTTP Request Defaults
├── HTTP Header Manager
├── HTTP Cookie Manager
├── CSV Data Set Config
├── Thread Group (User Flow)
│ ├── Transaction Controller (Login)
│ │ ├── HTTP Request (GET /login)
│ │ ├── HTTP Request (POST /auth/login)
│ │ ├── Response Assertion
│ │ ├── JSON Extractor (token)
│ │ └── JSR223 PostProcessor
│ ├── Constant Timer (Think Time)
│ ├── Transaction Controller (Browse Products)
│ │ ├── HTTP Request (GET /products)
│ │ └── Response Assertion
│ └── Transaction Controller (Checkout)
│ ├── HTTP Request (POST /cart)
│ ├── HTTP Request (POST /checkout)
│ └── Response Assertion
├── View Results Tree (debug only)
├── Summary Report
└── Backend Listener (InfluxDB)
Thread Group Configuration
Standard Load Test
<ThreadGroup guiclass="ThreadGroupGui" testclass="ThreadGroup" testname="Load Test Users">
<intProp name="ThreadGroup.num_threads">100</intProp>
<intProp name="ThreadGroup.ramp_time">300</intProp>
<boolProp name="ThreadGroup.scheduler">true</boolProp>
<stringProp name="ThreadGroup.duration">1800</stringProp>
<stringProp name="ThreadGroup.delay">0</stringProp>
<boolProp name="ThreadGroup.same_user_on_next_iteration">false</boolProp>
</ThreadGroup>
Stepping Thread Group (Ultimate Thread Group Plugin)
Use the Ultimate Thread Group plugin for complex ramp patterns:
- Start Threads Count -- Number of threads to add at each step
- Initial Delay -- Wait before starting this step
- Startup Time -- Time to ramp up these threads
- Hold Load For -- Duration to maintain these threads
- Shutdown Time -- Time to ramp down these threads
Example pattern for a load test:
| Start | Delay | Startup | Hold | Shutdown |
|---|---|---|---|---|
| 25 | 0s | 60s | 300s | 30s |
| 25 | 60s | 60s | 240s | 30s |
| 25 | 120s | 60s | 180s | 30s |
| 25 | 180s | 60s | 120s | 30s |
HTTP Request Defaults
Always configure HTTP Request Defaults at the test plan level:
Protocol: https
Server Name: ${BASE_URL}
Port Number: ${PORT}
Content Encoding: UTF-8
Implementation: HttpClient4
Connect Timeout: 5000
Response Timeout: 30000
Extractors and Correlation
JSON Extractor
Extract values from JSON responses:
Variable Names: auth_token
JSON Path Expressions: $.token
Match No.: 1
Default Values: NOT_FOUND
Regular Expression Extractor
For HTML or non-JSON responses:
Reference Name: csrf_token
Regular Expression: name="csrf_token" value="(.+?)"
Template: $1$
Match No.: 1
Default Value: NOT_FOUND
Boundary Extractor
Simpler alternative to regex:
Reference Name: session_id
Left Boundary: sessionId=
Right Boundary: ;
Match No.: 1
Using Extracted Values
In subsequent requests:
Header: Authorization: Bearer ${auth_token}
URL Path: /api/users/${user_id}
Body: {"sessionId": "${session_id}"}
Assertions
Response Assertion
Apply to: Main sample only
Field to Test: Response Code
Pattern Matching Rules: Equals
Patterns to Test: 200
JSON Assertion
Assert JSON Path exists: $.data.id
Expected Value: (leave empty to just check existence)
Additionally assert value: false
Duration Assertion
Duration in milliseconds: 2000
Size Assertion
Apply to: Main sample only
Size to Assert: Response body
Type of Comparison: < (less than)
Size in bytes: 1048576
Timers
Constant Timer
Thread Delay: 1000
Gaussian Random Timer
More realistic than constant timers:
Deviation: 500
Constant Delay Offset: 2000
This produces delays between ~1000ms and ~3000ms with most around 2000ms.
Uniform Random Timer
Random Delay Maximum: 3000
Constant Delay Offset: 1000
Produces delays between 1000ms and 4000ms uniformly distributed.
Parameterization with CSV
CSV Data Set Config
Filename: data/users.csv
File Encoding: UTF-8
Variable Names: username,password,role
Ignore first line: true
Delimiter: ,
Allow quoted data: true
Recycle on EOF: true
Stop thread on EOF: false
Sharing mode: All threads
CSV File Format
username,password,role
user1@example.com,Pass123!,user
user2@example.com,Pass456!,user
admin@example.com,Admin789!,admin
JSR223 Scripting (Groovy)
Pre-Processor -- Generate Dynamic Data
import java.time.Instant
import java.util.UUID
vars.put("request_id", UUID.randomUUID().toString())
vars.put("timestamp", Instant.now().toString())
vars.put("random_email", "user_${__Random(1000,9999)}@example.com")
// Generate random order amount
def amount = (Math.random() * 1000 + 10).round(2)
vars.put("order_amount", amount.toString())
Post-Processor -- Parse Complex Responses
import groovy.json.JsonSlurper
def response = prev.getResponseDataAsString()
def json = new JsonSlurper().parseText(response)
if (json.data && json.data.size() > 0) {
def firstItem = json.data[0]
vars.put("product_id", firstItem.id.toString())
vars.put("product_name", firstItem.name)
log.info("Extracted product: ${firstItem.name}")
} else {
log.warn("No products found in response")
prev.setSuccessful(false)
prev.setResponseMessage("No products in response")
}
Assertion -- Custom Validation
import groovy.json.JsonSlurper
def response = prev.getResponseDataAsString()
def json = new JsonSlurper().parseText(response)
// Validate response structure
assert json.data != null : "Response missing 'data' field"
assert json.data.size() > 0 : "Data array is empty"
assert json.total >= json.data.size() : "Total count inconsistent"
// Validate each item
json.data.each { item ->
assert item.id != null : "Item missing ID"
assert item.name?.trim() : "Item missing name"
assert item.price > 0 : "Item price must be positive"
}
Distributed Testing
Master-Slave Configuration
On the master machine (jmeter.properties):
remote_hosts=slave1:1099,slave2:1099,slave3:1099
server.rmi.ssl.disable=true
mode=StrippedBatch
On each slave machine:
# Start JMeter server
jmeter-server -Djava.rmi.server.hostname=<slave-ip>
Run distributed test:
jmeter -n -t test-plans/load-test.jmx \
-R slave1,slave2,slave3 \
-l results/distributed-results.jtl \
-e -o reports/distributed-report
Command-Line Execution
# Basic run
jmeter -n -t test-plans/load-test.jmx -l results/results.jtl
# With properties override
jmeter -n -t test-plans/load-test.jmx \
-JBASE_URL=staging.example.com \
-JTHREADS=200 \
-JRAMPUP=300 \
-JDURATION=1800 \
-l results/results.jtl
# Generate HTML report after test
jmeter -g results/results.jtl -o reports/html-report
# Run with HTML report generation
jmeter -n -t test-plans/load-test.jmx \
-l results/results.jtl \
-e -o reports/html-report
# With specific log level
jmeter -n -t test-plans/load-test.jmx \
-l results/results.jtl \
-LDEBUG
Listeners and Reporting
Backend Listener (InfluxDB)
For real-time monitoring with Grafana:
Backend Listener Implementation: org.apache.jmeter.visualizers.backend.influxdb.InfluxdbBackendListenerClient
influxdbUrl: http://influxdb:8086/write?db=jmeter
application: my-app
measurement: jmeter
summaryOnly: false
samplersRegex: .*
Custom JTL Configuration
In jmeter.properties or user.properties:
jmeter.save.saveservice.output_format=csv
jmeter.save.saveservice.response_data=false
jmeter.save.saveservice.samplerData=false
jmeter.save.saveservice.requestHeaders=false
jmeter.save.saveservice.url=true
jmeter.save.saveservice.responseHeaders=false
jmeter.save.saveservice.timestamp_format=ms
jmeter.save.saveservice.successful=true
jmeter.save.saveservice.label=true
jmeter.save.saveservice.code=true
jmeter.save.saveservice.message=true
jmeter.save.saveservice.threadName=true
jmeter.save.saveservice.time=true
jmeter.save.saveservice.connect_time=true
jmeter.save.saveservice.latency=true
jmeter.save.saveservice.bytes=true
Best Practices
- Never run load tests from the GUI -- GUI mode is for script development only.
- Remove all listeners during actual tests -- Listeners consume memory under load.
- Use Transaction Controllers -- Group related requests for meaningful metrics.
- Parameterize test data -- Use CSV files and variables for all test data.
- Add think times -- Real users pause between actions.
- Validate with assertions -- Every request should be verified for correctness.
- Use HTTP Request Defaults -- Centralize common settings.
- Enable cookies -- Add HTTP Cookie Manager for session management.
- Increase JVM heap -- Set
-Xms1g -Xmx4gfor large load tests. - Monitor the load generator -- Ensure the JMeter machine is not the bottleneck.
Anti-Patterns to Avoid
- Running tests from GUI -- GUI mode adds overhead and skews results.
- Too many listeners -- View Results Tree with response data consumes massive memory.
- No correlation -- Hardcoded session IDs cause authentication failures.
- No think time -- Unrealistic load pattern with machine-gun requests.
- Ignoring ramp-up -- Starting all threads simultaneously overloads the system unnaturally.
- Single machine overload -- Too many threads on one machine produces unreliable results.
- Not clearing results between runs -- Old results mixed with new cause confusion.
- Hardcoded data -- Every user sending the same data is unrealistic.
- Ignoring connection timeouts -- Without timeouts, threads hang forever.
- Not monitoring JMeter itself -- JMeter GC pauses affect results accuracy.
Key Metrics to Monitor
- Throughput -- Requests per second (should plateau, not drop)
- Response Time -- Average, median, 90th, 95th, 99th percentiles
- Error Rate -- Percentage of failed requests
- Active Threads -- Should match the configured ramp pattern
- Connect Time -- Time to establish TCP connection
- Latency -- Time to first byte of response
- Bandwidth -- Network throughput (bytes/sec)
- Server Hits/sec -- Rate of requests hitting the server
先判断是否适合
作者设计意图
作者的方法与取舍
边界和复核