Chương 11 Trung Cấp
API Testing
Kiểm thử API là kỹ năng bắt buộc của QA hiện đại — nhanh hơn UI testing, phát hiện bug sớm hơn ở tầng backend.
🌐 HTTP Fundamentals Required
| Method | Mục đích | Idempotent? | Request Body? |
|---|---|---|---|
| GET | Retrieve data — không thay đổi state | Yes | No |
| POST | Create resource mới | No | Yes |
| PUT | Update toàn bộ resource (replace) | Yes | Yes |
| PATCH | Update một phần resource | Depends | Yes |
| DELETE | Xóa resource | Yes | Optional |
Status Codes cần nhớ:
2xx Success200 OK, 201 Created, 204 No Content (DELETE success), 202 Accepted (async)3xx Redirect301 Moved Permanently, 302 Found (temporary redirect), 304 Not Modified (cache hit)4xx Client Error400 Bad Request (malformed), 401 Unauthorized, 403 Forbidden, 404 Not Found, 409 Conflict, 422 Unprocessable Entity (validation fail)5xx Server Error500 Internal Server Error (bug!), 502 Bad Gateway, 503 Service Unavailable, 504 Gateway Timeout
Headers quan trọng:
Content-Type: application/json— Request body là JSONAuthorization: Bearer <token>— JWT/OAuth tokenAccept: application/json— Client muốn nhận JSONX-Request-ID: uuid— Correlation ID cho tracingCache-Control: no-cache— Không dùng cached response
📮 Postman Advanced
- Environments & VariablesTạo Environment: Dev, Staging, Production. Variables:
{{base_url}},{{token}},{{user_id}}. Switch environment = switch full config set instantly. - Pre-request ScriptsJavaScript chạy trước request. Dùng để: generate dynamic data, set variables từ kết quả request trước, compute signature/hash.
- Tests Tab (Assertions)JavaScript assertions chạy sau response. Xem code example dưới.
- Collection RunnerChạy toàn bộ collection theo thứ tự. Set iterations, delay giữa requests, sử dụng CSV data file.
- Chaining RequestsExtract data từ response:
pm.environment.set("userId", pm.response.json().id). Request sau dùng{{userId}}.
// Postman Tests Tab — Common Assertions
// Status code
pm.test("Status is 200", () => pm.response.to.have.status(200));
pm.test("Status is 2xx", () => pm.response.to.be.success);
// Response time
pm.test("Response time < 500ms", () =>
pm.expect(pm.response.responseTime).to.be.below(500)
);
// Body assertions
const body = pm.response.json();
pm.test("Has id field", () => pm.expect(body.id).to.exist);
pm.test("Email is correct", () =>
pm.expect(body.email).to.eql("test@example.com")
);
pm.test("Status is active", () =>
pm.expect(body.status).to.be.oneOf(["active", "pending"])
);
// Set variable for next request
pm.environment.set("createdId", body.id);
🔑 Authentication Types
- API KeySimple static key. Truyền qua Header:
X-API-Key: abc123hoặc query param?api_key=abc123. Test: không có key, key sai, key hết hạn. - Bearer Token (JWT)Token sau login:
Authorization: Bearer eyJhbGc.... JWT gồm header.payload.signature. Decode payload để verify claims. Test: expired token, tampered payload, wrong signature. - Basic Auth
Authorization: Basic base64(username:password). Chỉ an toàn qua HTTPS. Legacy systems. Test: wrong credentials, empty fields. - OAuth 2.0Authorization Code (web apps), Client Credentials (server-to-server), Implicit (deprecated), PKCE (mobile/SPA). Test: authorization flow, token refresh, scope validation.
- OAuth 2.0 Flow1. Client redirects user → Auth Server. 2. User authenticates. 3. Auth Server returns code. 4. Client exchanges code → access_token + refresh_token. 5. Client uses access_token.
🧪 Comprehensive API Test Scenarios
- Happy Path: Valid request → correct status (200/201), correct response schema, correct data values
- Auth: No token → 401 | Wrong token → 401 | Expired token → 401 | Valid token wrong role → 403
- Validation: Missing required field → 400/422 | Wrong data type → 400 | String too long → 400 | Negative number where positive required → 400
- Not Found: Non-existent ID → 404, not 500
- Conflict: Create duplicate (same email) → 409, meaningful error message
- Idempotency: DELETE same ID twice → second call returns 404, not 500
- Pagination: page=1, page=99999 (beyond data), limit=0, limit=-1, limit=10000 (too large)
- Filter/Sort: Sort by invalid field → 400 | Filter with SQL injection attempt → 400 or sanitized
- Large payload: Request body 50MB → should return 413 Payload Too Large
- Special chars: Unicode, emoji, null bytes in string fields
- Response schema: All expected fields present | No sensitive data exposed (passwords, tokens, PII)
- Rate limiting: Send 100+ requests quickly → should get 429 Too Many Requests with Retry-After header
🏆 Senior Insight: Contract Testing
Senior QA biết về Consumer-Driven Contract Testing (Pact.io): Consumer định nghĩa "expectations" về API, Provider verify expectations đó được satisfied. Khi microservices evolve, contracts prevent breaking changes. Đây là layer testing giữa unit test và integration test.
📊 GraphQL Testing
GraphQL khác REST: 1 endpoint, client specify exactly what data needed.
# GraphQL Query
{
user(id: "123") {
id
name
email
orders {
id
total
status
}
}
}
# GraphQL Mutation
mutation {
createOrder(input: {
userId: "123"
items: [{productId: "456", quantity: 2}]
}) {
id
status
total
}
}
GraphQL-specific Test Cases:
- Query non-existent field → error với clear message, không crash
- Deeply nested query (n+1 problem) → performance check
- Introspection disabled in production → security best practice
- Query complexity limit — overly complex queries blocked
- Mutation idempotency — double submit mutation
🤖 API Test Automation
- Newman CLIChạy Postman collection từ command line:
newman run collection.json -e env.json --reporters cli,html. Tích hợp vào CI/CD pipeline. - GitHub ActionsTrigger Newman run on PR. Report kết quả vào PR comment. Fail build nếu có test failure.
- Playwright API TestingPlaywright có built-in API testing:
const response = await request.get('/api/users');— Kết hợp UI và API trong cùng framework.
✏️ Bài Tập
📝 Bài Tập: Postman Collection
Tạo Postman collection test cho một Users API với endpoints: GET /users, POST /users, GET /users/:id, PUT /users/:id, DELETE /users/:id.
- Viết test assertions trong Tests tab cho POST /users (successful creation): status code, response body fields, response time
- Viết Pre-request Script để generate random email cho mỗi test run tránh duplicate
- Chain requests: POST /users → lấy ID từ response → dùng ID trong GET /users/:id
- List 8 negative test cases cho DELETE /users/:id endpoint