DEV Community

Cover image for Kiểm thử hồi quy API: Phát hiện sớm thay đổi gây lỗi
Sebastian Petrus
Sebastian Petrus

Posted on • Originally published at apidog.com

Kiểm thử hồi quy API: Phát hiện sớm thay đổi gây lỗi

Bạn vừa đổi tên một trường trong một endpoint. Code build thành công, tính năng mới chạy ổn, deployment không lỗi. Hai ngày sau, ứng dụng mobile crash vì trường đó trước đây là chuỗi nhưng giờ thành object. Đây là lỗi hồi quy API: thay đổi tưởng như cục bộ nhưng phá vỡ hợp đồng mà client đang phụ thuộc.

Dùng thử Apidog hôm nay

Kiểm thử hồi quy API giúp bắt những lỗi này trước khi chúng đến tay người dùng. Bạn lưu một bộ kiểm thử mô tả hành vi hiện tại của API, sau đó chạy lại bộ đó sau mỗi thay đổi. Nếu cấu trúc response, status code hoặc giá trị quan trọng khác với baseline, pipeline sẽ fail và chỉ ra endpoint bị ảnh hưởng.

Kiểm thử hồi quy API là gì?

Kiểm thử hồi quy nghĩa là chạy lại các test đã từng pass để xác nhận hành vi hiện có vẫn được giữ nguyên sau thay đổi.

Với API, “hành vi hiện có” chính là hợp đồng HTTP mà client phụ thuộc vào:

  • Route
  • Method
  • Status code
  • Response schema
  • Field name
  • Data type
  • Giá trị quan trọng như id, status, total

API thường bị hồi quy vì các thay đổi nhỏ:

  • Đổi tên một field JSON
  • Refactor làm 200 thành 204
  • Rule validation mới từ chối input cũ
  • ORM upgrade làm đổi format ngày tháng
  • Dependency update làm đổi error message mà client đang parse

Những lỗi này không xuất hiện ở compile time. Chúng xuất hiện khi client tích hợp với API.

Điểm khác biệt: kiểm thử hồi quy API hẹp hơn kiểm thử hồi quy phần mềm nói chung. Bạn không kiểm lại toàn bộ business logic hay UI. Bạn chỉ kiểm phần giao diện HTTP mà hệ thống khác gọi vào. Vì phạm vi hẹp, bộ test có thể chạy trên mỗi commit hoặc pull request.

Nên baseline những gì?

Một bộ regression test tốt không nên assert mọi thứ trong payload. Hãy assert những gì có thể làm hỏng client.

Baseline nên gồm 4 lớp sau.

1. Status code

Mỗi endpoint phải trả về status code đã biết với input đã biết.

Ví dụ:

POST /v1/users -> 201
GET /v1/users/42 -> 200
DELETE /v1/users/42 -> 204
Enter fullscreen mode Exit fullscreen mode

Nếu 201 đổi thành 200, hoặc 200 đổi thành 500, đó là hồi quy ngay cả khi response body vẫn có vẻ hợp lệ.

2. Response schema

Kiểm cấu trúc và kiểu dữ liệu:

  • Field có tồn tại không
  • Field có bị đổi tên không
  • Field là string, number, array hay object
  • Object có bị lồng khác đi không

Schema drift là một trong những lỗi hồi quy API phổ biến nhất.

3. Giá trị trường quan trọng

Không cần khóa mọi giá trị. Chỉ assert các giá trị mang ý nghĩa hợp đồng:

  • id phải tồn tại
  • email phải là string đúng format
  • status phải thuộc enum cho phép
  • total phải là number
  • roles phải là array

Ví dụ baseline tối thiểu cho một endpoint:

GET /v1/users/42 -> 200

body.id       phải tồn tại, kiểu number
body.email    phải tồn tại, kiểu string, đúng format email
body.status   là một trong ["active", "pending", "suspended"]
body.roles    kiểu array
response time < 800 ms
Enter fullscreen mode Exit fullscreen mode

Nếu bất kỳ dòng nào fail sau một thay đổi, bạn đã có một regression signal rõ ràng.

Để viết assertion cho response body chi tiết hơn, xem các xác nhận API.

4. Hợp đồng API

Nếu bạn có OpenAPI spec, hãy dùng nó làm nguồn sự thật.

Ví dụ:

  • Spec nói email là required nhưng API không trả về nữa → contract violation
  • Spec nói createdAt là string date-time nhưng API trả về number → contract violation
  • Spec nói response là array nhưng API trả về object → contract violation

Xem thêm kiểm thử hợp đồng API để biến OpenAPI spec thành contract test.

Nguyên tắc thực tế:

Assert những gì có thể làm hỏng client, không assert mọi thứ tình cờ có trong payload hôm nay.

Ví dụ createdAt thay đổi theo mỗi request. Đừng assert giá trị cố định. Hãy assert type và format.

Kiểm thử thủ công hay tự động?

Bạn có thể kiểm thử hồi quy thủ công bằng cách mở API client, replay vài request đã lưu và kiểm response bằng mắt. Cách này ổn với một endpoint, nhưng nhanh chóng hỏng khi có nhiều endpoint.

Vấn đề của test thủ công:

  • Dễ bỏ sót case nhàm chán
  • Không chạy đều trên mỗi thay đổi
  • Không chạy lúc 2 giờ sáng khi dependency update được merge
  • Không scale khi API tăng số endpoint

Kiểm thử tự động giải quyết bằng cách ghi lại test một lần và chạy lại trên:

  • Mỗi push
  • Mỗi pull request
  • Mỗi merge vào main
  • Mỗi deployment
  • Job nightly nếu cần full coverage
Tiêu chí Thủ công Tự động
Chạy trên mỗi thay đổi Không, phụ thuộc vào kỷ luật Có, theo mặc định
Phạm vi bao phủ Vài endpoint Toàn bộ test suite
Chi phí mỗi lần chạy Phút của con người Giây tính toán
Bắt lỗi ngoài giờ làm việc Không
Nỗ lực ban đầu Thấp Trung bình

Với bất kỳ API nào có client thật, hãy tự động hóa regression test.

Xây dựng bộ kiểm thử hồi quy có thể tái sử dụng

Một regression suite nên là tập hợp các request đã lưu, có assertion, được nhóm để chạy cùng nhau.

Cấu trúc nên hướng tới tái sử dụng.

Nhóm theo tài nguyên

Thay vì nhóm theo feature ticket, hãy nhóm theo resource:

/users
/orders
/payments
/auth
Enter fullscreen mode Exit fullscreen mode

Khi thay đổi user service, bạn biết ngay nhóm test nào cần chú ý.

Dùng biến môi trường

Không hard-code các giá trị thay đổi theo môi trường.

Nên đưa các giá trị này vào environment:

baseUrl
authToken
tenantId
userId
Enter fullscreen mode Exit fullscreen mode

Ví dụ:

{{baseUrl}}/v1/users/{{userId}}
Authorization: Bearer {{authToken}}
Enter fullscreen mode Exit fullscreen mode

Nhờ vậy cùng một suite có thể chạy trên:

  • Local
  • Staging
  • Production smoke test

Xâu chuỗi request phụ thuộc nhau

Một flow thực tế thường là:

POST /users      -> tạo user
GET /users/{id}  -> đọc lại user
PATCH /users/{id}-> cập nhật user
DELETE /users/{id}-> xóa user
Enter fullscreen mode Exit fullscreen mode

Hãy trích xuất id từ response tạo mới và truyền vào request tiếp theo.

Pseudo flow:

1. POST /v1/users
2. Save body.id as userId
3. GET /v1/users/{{userId}}
4. Assert body.id == {{userId}}
5. PATCH /v1/users/{{userId}}
6. DELETE /v1/users/{{userId}}
Enter fullscreen mode Exit fullscreen mode

Cách này bắt được lỗi chỉ xuất hiện trong chuỗi request, không phải khi test từng endpoint riêng lẻ. Đây là phần giao nhau giữa regression testing và kiểm thử tích hợp API.

Dùng data-driven test cho validation

Nếu một endpoint có nhiều input case, đừng tạo 10 request gần giống nhau. Hãy dùng một request và một bảng dữ liệu.

Ví dụ CSV:

email,expectedStatus
alice@example.com,201
bob@test.co,201
not-an-email,422
,422
a@b,422
Enter fullscreen mode Exit fullscreen mode

Một request, năm test case, năm assertion cho status code.

Khi phát hiện edge case mới, chỉ cần thêm một dòng vào CSV.

Giữ suite đủ nhanh

Regression suite mất 20 phút sẽ dễ bị bỏ qua. Hãy tối ưu để suite chạy nhanh trên pull request:

  • Mock dependency bên thứ ba chậm
  • Chạy request độc lập song song nếu công cụ hỗ trợ
  • Giữ full end-to-end flow cho nightly run
  • Tách smoke regression và full regression

Chạy regression suite trong CI

Regression test chỉ chạy trên laptop của bạn thì chỉ bảo vệ laptop của bạn. Hãy đưa nó vào CI để chạy trên pull request và merge vào nhánh chính.

Mẫu triển khai chung:

  1. Cài headless runner
  2. Trỏ runner đến test suite đã lưu
  3. Chọn environment
  4. Chạy suite
  5. Fail build nếu assertion fail
  6. Xuất report cho CI đọc

Apidog cung cấp CLI runner cho workflow này.

Cài bằng Node:

npm install -g apidog-cli
Enter fullscreen mode Exit fullscreen mode

Chạy một test scenario hoặc test suite bằng ID:

apidog run \
  --access-token "$APIDOG_ACCESS_TOKEN" \
  -t 123456 \
  -e 789012 \
  -r cli,html,junit
Enter fullscreen mode Exit fullscreen mode

Ý nghĩa tham số:

  • --access-token: dùng để xác thực. Lưu trong CI secret, không commit vào repo.
  • -t: ID của scenario, folder hoặc test suite cần chạy.
  • -e: ID environment, ví dụ staging hoặc production.
  • -r: định dạng report.
    • cli: in kết quả ra console
    • html: tạo report dễ đọc
    • junit: xuất XML để CI hiển thị pass/fail theo từng test

Ví dụ GitHub Actions chạy trên mỗi pull request:

name: API Regression

on: [pull_request]

jobs:
  regression:
    runs-on: ubuntu-latest

    steps:
      - uses: actions/checkout@v6

      - uses: actions/setup-node@v6
        with:
          node-version: '22'

      - run: npm install -g apidog-cli

      - run: |
          apidog run \
            --access-token "$APIDOG_ACCESS_TOKEN" \
            -t 123456 \
            -e 789012 \
            -r cli,junit
        env:
          APIDOG_ACCESS_TOKEN: ${{ secrets.APIDOG_ACCESS_TOKEN }}
Enter fullscreen mode Exit fullscreen mode

Nếu test fail, runner thoát với exit code khác 0, job chuyển đỏ và pull request bị chặn.

Để có pipeline CI/CD đầy đủ hơn, xem Apidog CLI cho CI/CDcách tự động hóa kiểm thử API trong GitHub Actions.

Nếu suite dùng file dữ liệu, truyền bằng -d:

apidog run \
  --access-token "$APIDOG_ACCESS_TOKEN" \
  -t 123456 \
  -e 789012 \
  -d ./test-data/emails.csv \
  -r cli,junit
Enter fullscreen mode Exit fullscreen mode

Nếu muốn chạy test theo branch API riêng, dùng --branch. Nếu muốn lưu lịch sử run trên cloud, thêm --upload-report.

So sánh schema và hợp đồng

Assertion bắt lỗi hồi quy trong runtime behavior. Schema comparison bắt lỗi hồi quy trong định nghĩa API, thường ngay từ pull request.

Workflow nên là:

  1. OpenAPI spec được version trong repo
  2. Pull request chỉnh sửa spec
  3. CI so sánh spec mới với spec trước đó
  4. Công cụ phân loại thay đổi:
    • Non-breaking
    • Potentially breaking
    • Breaking
  5. Reviewer thấy rõ thay đổi thay vì đọc một khối YAML lớn

Ví dụ thay đổi an toàn:

Thêm field optional user.avatarUrl
Enter fullscreen mode Exit fullscreen mode

Ví dụ thay đổi gây lỗi:

Xóa user.phone
Đổi user.id từ number sang string
Biến user.email từ optional thành required
Đổi response 200 từ object sang array
Enter fullscreen mode Exit fullscreen mode

Kết hợp schema comparison với contract test trên API thật:

  • Spec phát hiện thay đổi có chủ đích trong hợp đồng
  • Contract test phát hiện implementation đang lệch khỏi spec

Breaking change không phải lúc nào cũng là bug. Có lúc bạn cố ý xóa field hoặc đổi kiểu dữ liệu. Nhưng thay đổi đó cần đi qua versioning và deprecation, không nên xuất hiện bất ngờ với client.

Xem thêm cách tạo phiên bản và ngừng hỗ trợ API ở quy mô lớn.

Cách Apidog hỗ trợ regression testing

Apidog gom các phần cần thiết vào cùng một workspace:

  • Thiết kế API
  • Lưu request
  • Viết assertion
  • Xâu chuỗi scenario
  • Gắn dataset CSV/JSON
  • Validate response với schema
  • Chạy test suite bằng CLI trong CI

Bạn có thể xây dựng scenario trực quan:

  1. Gửi request tạo resource
  2. Trích xuất giá trị từ response, ví dụ body.id
  3. Truyền giá trị đó vào request tiếp theo
  4. Gắn assertion cho status code, schema và field
  5. Lưu scenario vào test suite
  6. Chạy suite bằng apidog-cli trong CI

Vì API design và test nằm trong cùng một project, bạn có thể validate response với schema đã lưu của endpoint mà không phải định nghĩa schema ở hai nơi.

Với data-driven test, bạn gắn CSV hoặc JSON vào scenario. Apidog chạy một case cho mỗi dòng dữ liệu.

apidog-cli chạy các test suite đã lưu ở chế độ headless. Nó không phải công cụ gửi request tương tác và không phải load generator. Nhiệm vụ của nó là replay regression suite và xuất kết quả để CI quyết định pass/fail.

Xem thêm hướng dẫn pipeline CI/CD của Apidog CLI.

Quy trình bắt đầu trong một buổi chiều

Bạn không cần xây lại toàn bộ chiến lược test. Bắt đầu bằng một workflow nhỏ.

Bước 1: Chọn 5 endpoint có traffic cao nhất

Ưu tiên endpoint có nhiều client gọi:

GET /users/{id}
POST /orders
GET /orders/{id}
POST /payments
POST /auth/login
Enter fullscreen mode Exit fullscreen mode

Rủi ro hồi quy thường tập trung ở nơi có nhiều tích hợp.

Bước 2: Lưu request và thêm assertion

Với mỗi endpoint, thêm assertion tối thiểu:

  • Status code
  • Response schema
  • 2-3 field quan trọng
  • Response time nếu cần

Ví dụ:

GET /v1/orders/1001 -> 200

body.id        phải tồn tại
body.total     kiểu number
body.status    thuộc ["created", "paid", "cancelled"]
body.items     kiểu array
Enter fullscreen mode Exit fullscreen mode

Bước 3: Thêm một flow có chuỗi request

Chọn resource cốt lõi và test CRUD:

Create -> Read -> Update -> Delete
Enter fullscreen mode Exit fullscreen mode

Flow này bắt lỗi giữa các request mà test endpoint riêng lẻ không thấy.

Bước 4: Thêm dataset cho endpoint có validation phức tạp

Ví dụ với email, amount, coupon code hoặc date range.

amount,expectedStatus
100,201
0,422
-1,422
999999,201
Enter fullscreen mode Exit fullscreen mode

Bước 5: Chạy trong CI trên pull request

Thêm job CI:

npm install -g apidog-cli

apidog run \
  --access-token "$APIDOG_ACCESS_TOKEN" \
  -t 123456 \
  -e 789012 \
  -r cli,junit
Enter fullscreen mode Exit fullscreen mode

Lưu token trong secret:

APIDOG_ACCESS_TOKEN
Enter fullscreen mode Exit fullscreen mode

Nếu test fail, chặn merge.

Bước 6: Mở rộng suite từ lỗi thật

Mỗi bug hồi quy lọt ra production nên trở thành một test case mới.

Quy trình:

Bug xảy ra
-> Viết regression test tái hiện bug
-> Fix bug
-> Test pass
-> Giữ test trong suite
Enter fullscreen mode Exit fullscreen mode

Theo thời gian, suite phản ánh đúng những lỗi mà hệ thống của bạn thực sự dễ mắc.

Câu hỏi thường gặp

Kiểm thử hồi quy API khác gì kiểm thử hồi quy nói chung?

Kiểm thử hồi quy nói chung kiểm lại hành vi toàn hệ thống, gồm UI, business logic và integration. Kiểm thử hồi quy API chỉ tập trung vào HTTP interface: route, status code, response schema và các field quan trọng. Phạm vi hẹp giúp test đủ nhanh để chạy trên mỗi commit.

Nên chạy regression suite bao lâu một lần?

Chạy trên mọi thay đổi có thể ảnh hưởng đến API. Thực tế là:

  • Mỗi pull request
  • Mỗi merge vào main
  • Trước hoặc sau deployment
  • Nightly run cho suite lớn hơn

Giữ một core suite nhanh cho pull request và một full suite chậm hơn cho nightly.

Làm sao tránh test dễ vỡ?

Đừng assert dữ liệu không ổn định. Hãy assert contract.

Nên assert:

  • Status code
  • Field bắt buộc
  • Data type
  • Enum hợp lệ
  • Format như email hoặc date-time

Không nên assert:

  • Timestamp cố định
  • ID sinh ngẫu nhiên
  • Thứ tự array nếu API không cam kết thứ tự
  • Error message chi tiết nếu client không phụ thuộc vào nó

Có thể chạy regression test API mà không viết code không?

Có. Công cụ như Apidog cho phép tạo scenario và assertion trực quan, sau đó chạy headless trong CI bằng apidog-cli. Bạn lưu test qua giao diện, còn CLI replay suite trong pipeline.

Xử lý breaking change có chủ đích như thế nào?

Đừng để breaking change xuất hiện như một test failure bất ngờ. Hãy đưa nó qua quy trình versioning và deprecation:

  1. Gắn cờ thay đổi bằng schema comparison
  2. Thông báo cho consumer
  3. Thêm version mới hoặc field thay thế
  4. Duy trì field cũ trong thời gian chuyển tiếp
  5. Cập nhật regression baseline sau khi thay đổi được chấp nhận

Mục tiêu không phải là cấm mọi breaking change. Mục tiêu là làm cho chúng rõ ràng, được review và được triển khai có kiểm soát.

Top comments (0)