Tại sao Unit Test thôi là chưa đủ?
Nhiều lúc vừa code xong API, mình thấy rất tự tin vì Unit Test chạy xanh lè, Integration Test cũng mượt mà. Tuy nhiên, thực tế thường phũ phàng hơn nhiều. Chỉ cần một tester nhập payload “lạ” hoặc số âm vào ô yêu cầu số dương, server có thể lăn đùng ra báo lỗi 500 ngay lập tức.
Vấn đề nằm ở chỗ: Chúng ta thường chỉ viết test cho những trường hợp dự tính trước (Happy Path). Việc liệt kê đủ hàng nghìn tổ hợp dữ liệu để tìm lỗi logic là điều bất khả thi nếu làm thủ công.
Trong một dự án FastAPI thực tế, mình từng tin tưởng tuyệt đối vào Pydantic để validate dữ liệu. Nhưng khi dùng Schemathesis quét qua, nó phát hiện ngay lỗi xử lý số âm ở tham số limit gây crash câu lệnh SQL. Schemathesis giống như một tester cực kỳ khó tính. Nó dựa vào file OpenAPI (Swagger) để tự động sinh ra hàng trăm test case “quái chiêu” nhằm tìm điểm yếu của hệ thống.
Công cụ này sử dụng kỹ thuật Property-based Testing. Thay vì chỉ kiểm tra xem 1+1 có bằng 2 không, nó sẽ thử nghiệm với mọi số nguyên x và y. Mục tiêu là đảm bảo hàm luôn trả về đúng kiểu dữ liệu và không bao giờ làm sập chương trình.
Cài đặt Schemathesis trong 10 giây
Để bắt đầu, bạn cần một API đã có tài liệu chuẩn OpenAPI (thường là link /openapi.json hoặc /swagger.json). Nếu bạn dùng FastAPI hay Flask-Smorest, các framework này đã tự động tạo sẵn file cho bạn.
Cài đặt Schemathesis cực kỳ đơn giản qua pip:
pip install schemathesis
Giả sử bạn có ứng dụng FastAPI đang chạy tại http://127.0.0.1:8000. Hãy thử chạy lệnh sau để chứng kiến sức mạnh của nó:
st run http://127.0.0.1:8000/openapi.json
Nếu chưa có sẵn project, bạn hãy tạo nhanh file app.py để test thử:
from fastapi import FastAPI
app = FastAPI()
@app.get("/items/{item_id}")
def read_item(item_id: int, q: str = None):
# Lỗi logic: không xử lý khi item_id là số âm
if item_id < 0:
raise RuntimeError("Database crash!")
return {"item_id": item_id, "q": q}
Sau khi chạy app bằng uvicorn app:app, lệnh st run sẽ tóm gọn lỗi 500 chỉ trong vài giây khi nó thử truyền item_id = -1.
Cấu hình kiểm thử chuyên sâu cho dự án thực tế
Chạy lệnh CLI cơ bản là bước đầu, nhưng để bắt được các lỗi bảo mật hoặc sai lệch dữ liệu, bạn cần cấu hình chặt chẽ hơn.
1. Thắt chặt các quy tắc kiểm tra (Checks)
Mặc định Schemathesis chỉ tìm lỗi 500. Mình thường thêm các flag sau để đảm bảo API hoạt động đúng thiết kế:
st run http://127.0.0.1:8000/openapi.json \
--check not_a_server_error \
--check status_code_conformance \
--check content_type_conformance \
--check response_headers_conformance
- status_code_conformance: Đảm bảo mã lỗi trả về phải nằm trong danh sách bạn đã định nghĩa. Nếu bạn trả về 404 trong khi Swagger chỉ khai báo 200, Schemathesis sẽ báo lỗi ngay.
- content_type_conformance: Kiểm tra xem định dạng trả về (JSON, XML…) có đúng như cam kết trong tài liệu không.
2. Xử lý Authentication
Với các API yêu cầu đăng nhập, bạn có thể dễ dàng truyền Header trực tiếp vào lệnh chạy:
st run http://localhost:8000/openapi.json -H "Authorization: Bearer YOUR_TOKEN"
3. Tích hợp trực tiếp vào Pytest
Viết script Python giúp bạn linh hoạt hơn khi cần tùy chỉnh dữ liệu đầu vào (Data Generation) cho các quy trình CI/CD chuyên nghiệp.
import schemathesis
import pytest
schema = schemathesis.from_uri("http://127.0.0.1:8000/openapi.json")
@schema.parametrize()
def test_api(case):
response = case.call()
case.validate_response(response)
Một mẹo nhỏ khi làm dự án lớn: hãy dùng --hypothesis-max-examples=100. Con số này giúp giới hạn số lượng test case, tránh việc CI chạy quá lâu gây nghẽn pipeline.
Đọc hiểu kết quả và xử lý lỗi
Điểm mình thích nhất ở Schemathesis là khả năng tái hiện lỗi (Reproduce). Khi phát hiện sự cố, nó sẽ in ra một đoạn mã curl chính xác để bạn copy-paste và debug ngay lập tức.
Kết quả báo cáo thường bao gồm Falsifying example (payload cụ thể gây lỗi) và Stateful Testing. Tính năng Stateful cho phép nó thực hiện chuỗi request liên tiếp, ví dụ: tạo user xong rồi mới xóa, giúp tìm ra các lỗi logic về luồng dữ liệu.
Tự động hóa với GitHub Actions
Để ngăn chặn code lỗi bị merge, mình luôn cài đặt Schemathesis như một màng lọc khắt khe trong workflow. Nếu API vi phạm bất kỳ thỏa thuận nào trong OpenAPI, build sẽ thất bại ngay lập tức.
- name: Run Schemathesis Tests
run: st run http://localhost:8000/openapi.json --exitfirst
Bài học thực tế của mình là: Đừng bao giờ tin hoàn toàn vào tài liệu viết tay. Đôi khi Swagger bảo trả về String nhưng thực tế code lại trả về Null. Schemathesis sẽ là công cụ khách quan nhất để bắt những lỗi lệch pha này.
Đưa Schemathesis vào quy trình giúp team QA “thở phào” hơn và anh em dev cũng tự tin hơn mỗi khi release. Nếu bạn đang xây dựng REST API với Python, hãy thử quét project của mình một lần, kết quả có thể sẽ khiến bạn bất ngờ đấy.

