K6 现代性能测试工具
全面的 K6 性能测试示例,包括负载测试、压力测试、API性能测试和现代应用程序的高级测试模式
💻 K6 基础设置和配置 javascript
🟢 simple
⭐
完整的 K6 项目设置,包含配置文件、基础测试结构和性能测试基础知识
⏱️ 30 min
🏷️ k6, performance, setup, configuration
Prerequisites:
JavaScript basics, HTTP protocols, Performance testing concepts
// K6 Performance Testing - Basic Setup and Configuration
// 1. package.json - Dependencies
{
"name": "k6-performance-tests",
"version": "1.0.0",
"description": "Performance testing suite with K6",
"scripts": {
"test": "k6 run",
"test:smoke": "k6 run --vus 10 --duration 30s tests/smoke.js",
"test:load": "k6 run --vus 50 --duration 2m tests/load.js",
"test:stress": "k6 run --vus 100 --duration 5m tests/stress.js",
"test:spike": "k6 run --vus 200 --duration 10s tests/spike.js",
"test:soak": "k6 run --vus 30 --duration 30m tests/soak.js",
"report:html": "k6 run --out json=results.json tests/load.js && k6-reporter --json results.json"
},
"devDependencies": {
"k6": "^0.49.0",
"k6-reporter": "^2.2.0"
}
}
// 2. k6.config.js - Global Configuration
export const options = {
// Test execution options
vus: 10, // Virtual users
duration: '30s', // Test duration
// Stages for ramp-up/ramp-down
stages: [
{ duration: '10s', target: 10 }, // Ramp up
{ duration: '20s', target: 10 }, // Stay
{ duration: '10s', target: 0 }, // Ramp down
],
// Thresholds
thresholds: {
http_req_duration: ['p(95)<500'], // 95% of requests under 500ms
http_req_failed: ['rate<0.1'], // Error rate under 10%
checks: ['rate>0.95'], // 95% of checks should pass
},
// Headers
headers: {
'Content-Type': 'application/json',
'User-Agent': 'k6-performance-test/1.0',
},
};
// 3. tests/smoke.js - Basic Smoke Test
import http from 'k6/http';
import { check, sleep } from 'k6';
export const options = {
vus: 5,
duration: '30s',
thresholds: {
http_req_duration: ['p(95)<200'],
http_req_failed: ['rate<0.01'],
},
};
export default function () {
// Test API endpoint
const url = 'https://jsonplaceholder.typicode.com/posts/1';
const response = http.get(url);
// Basic checks
check(response, {
'status is 200': (r) => r.status === 200,
'response time < 200ms': (r) => r.timings.duration < 200,
'content-type is correct': (r) => r.headers['Content-Type'] === 'application/json; charset=utf-8',
});
sleep(1);
}
// 4. lib/config.js - Configuration Library
export const BASE_URL = 'https://api.example.com';
export const API_VERSION = 'v1';
export const DEFAULT_HEADERS = {
'Content-Type': 'application/json',
'Accept': 'application/json',
};
export const THRESHOLDS = {
SMOKE: {
http_req_duration: ['p(95)<200'],
http_req_failed: ['rate<0.01'],
},
LOAD: {
http_req_duration: ['p(95)<500'],
http_req_failed: ['rate<0.05'],
},
STRESS: {
http_req_duration: ['p(95)<1000'],
http_req_failed: ['rate<0.1'],
},
};
// 5. lib/utils.js - Utility Functions
import http from 'k6/http';
import { check } from 'k6';
export class ApiClient {
constructor(baseUrl, headers = {}) {
this.baseUrl = baseUrl;
this.headers = { ...DEFAULT_HEADERS, ...headers };
}
get(path, params = {}) {
const url = this.buildUrl(path, params);
return http.get(url, { headers: this.headers });
}
post(path, data = {}) {
const url = this.buildUrl(path);
const payload = JSON.stringify(data);
const params = {
headers: this.headers,
};
return http.post(url, payload, params);
}
put(path, data = {}) {
const url = this.buildUrl(path);
const payload = JSON.stringify(data);
const params = {
headers: this.headers,
};
return http.put(url, payload, params);
}
delete(path) {
const url = this.buildUrl(path);
return http.del(url, null, { headers: this.headers });
}
buildUrl(path, params = {}) {
const url = new URL(path, this.baseUrl);
Object.keys(params).forEach(key => {
url.searchParams.append(key, params[key]);
});
return url.toString();
}
// Common check patterns
checkSuccess(response, customChecks = {}) {
const defaultChecks = {
'status is successful': (r) => r.status >= 200 && r.status < 300,
'response time < 1s': (r) => r.timings.duration < 1000,
};
return check(response, { ...defaultChecks, ...customChecks });
}
}
💻 高级负载测试模式 javascript
🟡 intermediate
⭐⭐⭐
全面的负载测试模式,包括渐进式增长、尖峰测试、浸泡测试和压力测试
⏱️ 45 min
🏷️ k6, load testing, stress testing, spike testing
Prerequisites:
K6 basics, Performance testing concepts, JavaScript
// K6 Advanced Load Testing Patterns
import http from 'k6/http';
import { check, sleep } from 'k6';
import { Rate, Trend } from 'k6/metrics';
// Custom metrics
export let errorRate = new Rate('errors');
export let responseTime = new Trend('response_time');
// 1. Load Testing - Gradual Ramp Up
export function loadTest() {
export let options = {
stages: [
{ duration: '2m', target: 20 }, // Ramp up to 20 users
{ duration: '5m', target: 20 }, // Stay at 20 users
{ duration: '2m', target: 50 }, // Ramp up to 50 users
{ duration: '5m', target: 50 }, // Stay at 50 users
{ duration: '2m', target: 0 }, // Ramp down
],
thresholds: {
http_req_duration: ['p(95)<500'],
http_req_failed: ['rate<0.05'],
errors: ['rate<0.05'],
},
};
}
export default function () {
const response = http.get('https://api.example.com/users', {
headers: { 'Accept': 'application/json' },
});
const success = check(response, {
'status is 200': (r) => r.status === 200,
'response time < 500ms': (r) => r.timings.duration < 500,
});
errorRate.add(!success);
responseTime.add(response.timings.duration);
sleep(Math.random() * 3 + 1); // Random sleep 1-4s
}
// 2. Spike Testing - Sudden Traffic Surge
export function spikeTest() {
export let options = {
stages: [
{ duration: '1m', target: 10 }, // Normal load
{ duration: '30s', target: 100 }, // Spike
{ duration: '1m', target: 0 }, // Cool down
],
thresholds: {
http_req_duration: ['p(95)<1000'],
http_req_failed: ['rate<0.1'],
},
};
}
export default function () {
const payload = JSON.stringify({
name: `User_${__VU}`,
email: `user${__VU}@example.com`,
});
const response = http.post('https://api.example.com/users', payload, {
headers: { 'Content-Type': 'application/json' },
});
check(response, {
'status is 201': (r) => r.status === 201,
'user created': (r) => JSON.parse(r.body).id !== undefined,
});
}
// 3. Soak Testing - Extended Duration Test
export function soakTest() {
export let options = {
stages: [
{ duration: '5m', target: 5 }, // Ramp up
{ duration: '1h', target: 5 }, // Soak for 1 hour
{ duration: '5m', target: 0 }, // Ramp down
],
thresholds: {
http_req_duration: ['p(95)<300'],
http_req_failed: ['rate<0.01'],
checks: ['rate>0.99'],
},
};
}
export default function () {
// Simulate user journey
const responses = http.batch([
['GET', 'https://api.example.com/products'],
['GET', 'https://api.example.com/products/1'],
['GET', 'https://api.example.com/users/1'],
]);
responses.forEach(response => {
check(response, {
'status is 200': (r) => r.status === 200,
});
});
sleep(Math.random() * 5 + 2); // Random wait 2-7s
}
// 4. Stress Testing - Finding Breaking Point
export function stressTest() {
export let options = {
stages: [
{ duration: '2m', target: 20 }, // Warm up
{ duration: '5m', target: 50 }, // Load
{ duration: '5m', target: 100 }, // High load
{ duration: '5m', target: 200 }, // Stress
{ duration: '5m', target: 300 }, // Peak stress
{ duration: '5m', target: 0 }, // Recovery
],
thresholds: {
http_req_duration: ['p(95)<2000'],
http_req_failed: ['rate<0.2'],
},
};
}
export default function () {
const response = http.get('https://api.example.com/heavy-endpoint', {
timeout: '10s',
});
check(response, {
'status is successful': (r) => r.status >= 200 && r.status < 300,
'response time reasonable': (r) => r.timings.duration < 5000,
});
}
// 5. API Load Testing with Different Scenarios
export function apiLoadTest() {
export let options = {
vus: 50,
duration: '10m',
thresholds: {
'http_req_duration{type:read}': ['p(95)<300'],
'http_req_duration{type:write}': ['p(95)<800'],
'http_req_failed{type:read}': ['rate<0.01'],
'http_req_failed{type:write}': ['rate<0.05'],
},
};
}
export default function () {
// 80% read operations, 20% write operations
if (Math.random() < 0.8) {
// Read operation
const response = http.get('https://api.example.com/posts', {
tags: { type: 'read' },
});
check(response, {
'GET posts status': (r) => r.status === 200,
'posts returned': (r) => JSON.parse(r.body).length > 0,
});
} else {
// Write operation
const payload = JSON.stringify({
title: `Test Post ${__VU}`,
content: 'This is a test post created during load testing.',
authorId: Math.floor(Math.random() * 100) + 1,
});
const response = http.post('https://api.example.com/posts', payload, {
headers: { 'Content-Type': 'application/json' },
tags: { type: 'write' },
});
check(response, {
'POST posts status': (r) => r.status === 201,
'post created': (r) => JSON.parse(r.body).id !== undefined,
});
}
sleep(1);
}
💻 K6 API 性能测试 javascript
🔴 complex
⭐⭐⭐⭐
全面的 API 测试,包括 REST API、GraphQL、身份验证和数据驱动测试
⏱️ 60 min
🏷️ k6, api testing, rest, graphql
Prerequisites:
K6 advanced, API testing, GraphQL, Authentication
// K6 API Performance Testing
import http from 'k6/http';
import { check, sleep, group } from 'k6';
import { Rate } from 'k6/metrics';
// Custom metrics
export let errorRate = new Rate('errors');
export let apiErrors = new Rate('api_errors');
// Configuration
const BASE_URL = 'https://api.example.com';
const AUTH_TOKEN = 'your-api-token-here';
// 1. REST API Testing Suite
export function restApiTest() {
export let options = {
vus: 20,
duration: '5m',
thresholds: {
http_req_duration: ['p(95)<500'],
http_req_failed: ['rate<0.02'],
api_errors: ['rate<0.01'],
},
};
export default function () {
group('User Authentication', () => {
const loginResponse = http.post(`${BASE_URL}/auth/login`, JSON.stringify({
email: '[email protected]',
password: 'testpassword',
}), {
headers: { 'Content-Type': 'application/json' },
});
const loginSuccess = check(loginResponse, {
'login status is 200': (r) => r.status === 200,
'has token': (r) => JSON.parse(r.body).token !== undefined,
});
if (loginSuccess) {
const token = JSON.parse(loginResponse.body).token;
group('Authenticated API Calls', () => {
// Get user profile
const profileResponse = http.get(`${BASE_URL}/users/profile`, {
headers: {
'Authorization': `Bearer ${token}`,
'Content-Type': 'application/json',
},
});
check(profileResponse, {
'profile status is 200': (r) => r.status === 200,
'has user data': (r) => JSON.parse(r.body).id !== undefined,
});
// Update user profile
const updateResponse = http.put(`${BASE_URL}/users/profile`, JSON.stringify({
name: 'Updated Test User',
}), {
headers: {
'Authorization': `Bearer ${token}`,
'Content-Type': 'application/json',
},
});
check(updateResponse, {
'update status is 200': (r) => r.status === 200,
'profile updated': (r) => JSON.parse(r.body).name === 'Updated Test User',
});
});
}
apiErrors.add(!loginSuccess);
});
sleep(1);
}
}
// 2. GraphQL API Testing
export function graphqlApiTest() {
export let options = {
vus: 15,
duration: '3m',
thresholds: {
http_req_duration: ['p(95)<600'],
http_req_failed: ['rate<0.03'],
},
};
const GRAPHQL_URL = 'https://api.example.com/graphql';
export default function () {
// Query example
const query = `
query GetUserPosts($userId: ID!) {
user(id: $userId) {
id
name
email
posts {
id
title
content
createdAt
}
}
}
`;
const variables = {
userId: Math.floor(Math.random() * 100) + 1,
};
const response = http.post(GRAPHQL_URL, JSON.stringify({
query: query,
variables: variables,
}), {
headers: { 'Content-Type': 'application/json' },
});
check(response, {
'GraphQL status is 200': (r) => r.status === 200,
'has data': (r) => JSON.parse(r.body).data !== undefined,
'no GraphQL errors': (r) => JSON.parse(r.body).errors === undefined,
});
sleep(2);
}
}
// 3. Data-Driven API Testing
export function dataDrivenApiTest() {
export let options = {
vus: 10,
duration: '2m',
};
// Test data
const testUsers = [
{ email: '[email protected]', password: 'password1', role: 'admin' },
{ email: '[email protected]', password: 'password2', role: 'user' },
{ email: '[email protected]', password: 'password3', role: 'moderator' },
];
export default function () {
const user = testUsers[Math.floor(Math.random() * testUsers.length)];
group('User Authentication', () => {
const response = http.post(`${BASE_URL}/auth/login`, JSON.stringify({
email: user.email,
password: user.password,
}), {
headers: { 'Content-Type': 'application/json' },
tags: { user_role: user.role },
});
const success = check(response, {
'login successful': (r) => r.status === 200,
'token received': (r) => JSON.parse(r.body).token !== undefined,
'correct role': (r) => JSON.parse(r.body).user.role === user.role,
});
if (success) {
const token = JSON.parse(response.body).token;
// Perform role-specific actions
if (user.role === 'admin') {
adminActions(token);
} else if (user.role === 'user') {
userActions(token);
} else if (user.role === 'moderator') {
moderatorActions(token);
}
}
errorRate.add(!success);
});
sleep(3);
}
}
// Role-specific actions
function adminActions(token) {
group('Admin Actions', () => {
const response = http.get(`${BASE_URL}/admin/dashboard`, {
headers: { 'Authorization': `Bearer ${token}` },
tags: { action: 'admin_dashboard' },
});
check(response, {
'dashboard accessible': (r) => r.status === 200,
'has admin data': (r) => JSON.parse(r.body).adminStats !== undefined,
});
});
}
function userActions(token) {
group('User Actions', () => {
const response = http.get(`${BASE_URL}/user/profile`, {
headers: { 'Authorization': `Bearer ${token}` },
tags: { action: 'user_profile' },
});
check(response, {
'profile accessible': (r) => r.status === 200,
'has user data': (r) => JSON.parse(r.body).profile !== undefined,
});
});
}
function moderatorActions(token) {
group('Moderator Actions', () => {
const response = http.get(`${BASE_URL}/moderator/content`, {
headers: { 'Authorization': `Bearer ${token}` },
tags: { action: 'moderate_content' },
});
check(response, {
'content accessible': (r) => r.status === 200,
'has content list': (r) => Array.isArray(JSON.parse(r.body).content),
});
});
}
// 4. API Performance Testing with Multiple Endpoints
export function multiEndpointApiTest() {
export let options = {
vus: 30,
duration: '10m',
thresholds: {
'http_req_duration{endpoint:products}': ['p(95)<400'],
'http_req_duration{endpoint:orders}': ['p(95)<600'],
'http_req_duration{endpoint:users}': ['p(95)<300'],
'http_req_failed{endpoint:products}': ['rate<0.02'],
'http_req_failed{endpoint:orders}': ['rate<0.03'],
'http_req_failed{endpoint:users}': ['rate<0.01'],
},
};
export default function () {
// Product endpoints
http.batch([
['GET', `${BASE_URL}/products`, null, { tags: { endpoint: 'products' } }],
['GET', `${BASE_URL}/products/1`, null, { tags: { endpoint: 'products' } }],
]);
// Order endpoints
http.batch([
['GET', `${BASE_URL}/orders`, null, { tags: { endpoint: 'orders' } }],
['GET', `${BASE_URL}/orders/1`, null, { tags: { endpoint: 'orders' } }],
]);
// User endpoints
http.batch([
['GET', `${BASE_URL}/users`, null, { tags: { endpoint: 'users' } }],
['GET', `${BASE_URL}/users/1`, null, { tags: { endpoint: 'users' } }],
]);
sleep(2);
}
}