Một đường ống xanh (pipeline) chuyển giao một API bị lỗi còn tệ hơn là không có đường ống nào cả. Nó báo cho nhóm của bạn rằng mọi thứ đều ổn cho đến khi khách hàng gửi một yêu cầu hỗ trợ. Hầu hết các thiết lập kiểm thử API trong CI bắt đầu mạnh mẽ và dần dần mục nát: một vài endpoint được bao phủ, sau đó bộ kiểm thử trở nên không ổn định, ai đó thêm continue-on-error để ngừng tiếng ồn, và trong vòng một quý, các bài kiểm thử vẫn chạy nhưng không ai tin tưởng chúng. Đường ống xanh vì nó đã học cách bỏ qua lỗi.
Giải pháp không phải là thêm nhiều bài kiểm thử. Đó là một số quyết định về cách bạn thiết kế, chạy và kiểm soát các bài kiểm thử đó để chúng vẫn đáng tin cậy dưới áp lực thực tế, loại áp lực đến từ một bản vá nóng vào chiều thứ Sáu hoặc một thay đổi schema sâu ba lớp dịch vụ. Hướng dẫn này sẽ trình bày mười hai quyết định đó, kèm theo cấu hình cụ thể mà bạn có thể sao chép vào GitHub Actions, GitLab CI hoặc bất kỳ runner nào bạn đang sử dụng.
Điểm chung xuyên suốt tất cả chúng là: các bài kiểm thử API của bạn nên nằm cạnh hợp đồng API của bạn, chạy từ một lệnh di động duy nhất và báo lỗi lớn khi hợp đồng bị phá vỡ. Đó là quy trình làm việc chúng ta sẽ xây dựng với Apidog, một nền tảng API nơi bạn thiết kế đặc tả, viết các xác nhận (assertions) một cách trực quan và chạy toàn bộ bộ kiểm thử không giao diện (headless) trong CI thông qua Apidog CLI. Bạn thiết kế các bài kiểm thử một lần trong ứng dụng, sau đó chạy chính xác bộ kiểm thử đó trong bất kỳ pipeline nào chỉ với một lệnh duy nhất. Nếu bạn muốn theo dõi, hãy tải xuống Apidog và giữ API của riêng bạn tiện dụng.
Nếu CI/CD còn mới đối với bạn, phiên bản tóm tắt là: tích hợp liên tục (continuous integration) chạy các bài kiểm thử của bạn trên mỗi commit, và phân phối liên tục (continuous delivery) quảng bá bản dựng vượt qua các bài kiểm thử đó. Chúng tôi có một phân tích đầy đủ hơn trong bài viết CI/CD là gì và hoạt động như thế nào. Phần còn lại của bài viết này giả định bạn đã có một pipeline và muốn phần kiểm thử API thực sự phát huy giá trị của nó.
1. Đặt kiểm thử API vào pipeline, không phải trong một tab bạn quên mở
Thực hành tốt nhất đầu tiên là điều mà mọi người thường bỏ qua: chạy các bài kiểm thử API của bạn tự động, trên mỗi lần đẩy (push), mà không cần con người quyết định. Một bộ kiểm thử bạn chạy thủ công trước khi phát hành là một danh sách kiểm tra, không phải một mạng lưới an toàn. Đến lúc bạn nhớ chạy nó, thay đổi gây lỗi đã lùi lại sáu commit rồi.
Kết nối bộ kiểm thử vào giai đoạn quan trọng. Đối với hầu hết các nhóm, đó là trên các pull request, để một API bị lỗi sẽ chặn việc hợp nhất thay vì đi đến main. Đây là cấu trúc tối thiểu trong GitHub Actions:
name: Kiểm thử API
on:
pull_request:
branches: [main]
jobs:
api-tests:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '20'
- name: Cài đặt Apidog CLI
run: npm install -g apidog-cli
- name: Chạy bộ kiểm thử API
run: |
apidog run \
--access-token "$APIDOG_ACCESS_TOKEN" \
-t "$SCENARIO_ID" \
-e "$APIDOG_ENV_ID" \
-r cli,junit \
--out-dir ./test-results
env:
APIDOG_ACCESS_TOKEN: ${{ secrets.APIDOG_ACCESS_TOKEN }}
SCENARIO_ID: ${{ vars.SCENARIO_ID }}
APIDOG_ENV_ID: ${{ vars.APIDOG_ENV_ID }}
Đó là toàn bộ quá trình tích hợp. CLI thoát với mã 0 khi mọi xác nhận đều vượt qua và một mã khác 0 khi có bất kỳ xác nhận nào thất bại, vì vậy GitHub sẽ báo lỗi công việc (job) bằng màu đỏ khi có lỗi thực sự mà không cần cấu hình thêm. Chúng tôi trình bày thiết lập GitHub đầy đủ trong Cách tự động hóa kiểm thử API trong GitHub Actions; mẫu này có thể áp dụng cho bất kỳ runner nào.
Mục đích của thực hành tốt nhất thứ nhất là quyết định kiểm thử được thực hiện bởi máy, không phải bởi nhà phát triển. Con người có thể quên. Pipelines thì không.
2. Giữ lệnh chạy có tính di động trên các nhà cung cấp CI
Các pipeline di chuyển. Các nhóm chuyển từ Jenkins sang GitHub Actions, thêm GitLab cho một repo mới hoặc triển khai một runner tự host để tuân thủ. Nếu các bài kiểm thử API của bạn gắn chặt với hệ sinh thái plugin của một nhà cung cấp duy nhất, mỗi lần di chuyển đều có nghĩa là phải viết lại chúng.
Cách để tránh điều đó là biến lệnh gọi kiểm thử thành một lệnh shell duy nhất mà bất kỳ runner nào cũng có thể gọi. Với Apidog CLI, lệnh chạy bộ kiểm thử của bạn là giống nhau bất kể ai gọi nó:
apidog run --access-token "$APIDOG_ACCESS_TOKEN" -t "$SCENARIO_ID" -e "$ENV_ID" -r cli,junit
Dòng lệnh đó hoạt động trong bước run của GitHub Actions, khối script của GitLab, giai đoạn shell của Jenkins hoặc phần script của Travis. Chỉ có phần bao bọc bên ngoài nó thay đổi. Ví dụ, GitLab:
api-tests:
image: node:20
script:
- npm install -g apidog-cli
- apidog run --access-token "$APIDOG_ACCESS_TOKEN" -t "$SCENARIO_ID" -e "$ENV_ID" -r cli,junit
artifacts:
when: always
reports:
junit: ./test-results/*.xml
Bởi vì các công việc nặng nhọc (điều phối yêu cầu, xác nhận, phân giải môi trường) nằm trong CLI và định nghĩa kiểm thử nằm trong Apidog, tệp YAML pipeline của bạn sẽ gọn nhẹ. Khi bạn chuyển đổi nhà cung cấp, bạn chỉ cần sao chép sáu dòng, không phải sáu trăm. Biến thể Jenkins được trình bày chi tiết trong Cách tích hợp kiểm thử tự động của Apidog với Jenkins cho CI/CD nếu đó là ngăn xếp của bạn.
3. Xác nhận hành vi, không chỉ mã trạng thái
Một bài kiểm thử chỉ kiểm tra 200 OK sẽ vượt qua trong khi API của bạn trả về một mảng trống, sai đơn vị tiền tệ hoặc giá trị null nơi client mong đợi một đối tượng. Các bài kiểm thử chỉ dựa vào mã trạng thái là lý do lớn nhất khiến các pipeline xanh chuyển giao các phản hồi bị lỗi.
Các xác nhận thực sự kiểm tra hình dạng và nội dung của phản hồi: các trường tồn tại, kiểu dữ liệu của chúng, các giá trị quan trọng đối với người dùng. Trong Apidog, bạn xây dựng các xác nhận này một cách trực quan dựa trên phản hồi, vì vậy bạn đang xác nhận trên payload thực tế thay vì đoán JSONPath trong đầu. Một bài kiểm thử tra cứu đơn hàng vững chắc xác nhận rằng trạng thái là 200, order.total là một số, currency bằng giá trị bạn đã gửi và mảng items không trống. Mỗi điều đó là một xác nhận riêng biệt có thể thất bại độc lập, vì vậy một bản dựng đỏ sẽ cho bạn biết hợp đồng nào đã bị phá vỡ.
Ba quy tắc giúp các xác nhận duy trì hiệu lực theo thời gian:
- Xác nhận trên hợp đồng, không phải dữ liệu. Kiểm tra xem
totalcó phải là một số không, chứ không phải nó bằng49.99. Giá trị chính xác thay đổi; kiểu dữ liệu thì không. - Mỗi xác nhận chỉ tập trung vào một mối quan tâm. Gộp sáu kiểm tra vào một xác nhận sẽ che giấu điều gì đã thất bại.
- Bao phủ các trường hợp lỗi (unhappy path). Mã
400cho đầu vào xấu và401cho mã thông báo bị thiếu cũng là một phần của hợp đồng của bạn. Hãy kiểm thử để đảm bảo chúng vẫn hoạt động đúng.
Để tìm hiểu sâu hơn về cách viết các xác nhận có thể tồn tại qua các lần tái cấu trúc, hãy xem hướng dẫn của chúng tôi về các xác nhận API. Các xác nhận mạnh mẽ là yếu tố biến một bài kiểm thử sơ bộ (smoke test) thành một bài kiểm thử hợp đồng, và các bài kiểm thử hợp đồng là thứ bắt được những lỗi hồi quy quan trọng.
4. Quản lý môi trường và bí mật dưới dạng cấu hình, không bao giờ là các giá trị được mã hóa cứng
Các bài kiểm thử của bạn chạy trên các mục tiêu khác nhau: một stack cục bộ, một API staging, một endpoint kiểm thử sơ bộ (smoke endpoint) sản xuất. URL cơ sở, mã thông báo xác thực và ID tenant đều thay đổi giữa chúng. Việc mã hóa cứng bất kỳ điều nào trong số đó vào một bài kiểm thử là cách một bài kiểm thử staging vô tình tác động đến sản xuất, hoặc cách một mã thông báo kết thúc trong lịch sử git của bạn.
Giữ các môi trường dưới dạng cấu hình được đặt tên và đưa vào các điểm khác biệt. Trong Apidog, một môi trường chứa URL cơ sở và các biến cho một mục tiêu; bạn chọn môi trường nào mà một lần chạy CI sẽ sử dụng bằng cờ -e. Pipeline cung cấp mã thông báo truy cập từ kho bí mật của nó, không bao giờ từ một tệp trong repo:
apidog run \
--access-token "$APIDOG_ACCESS_TOKEN" \
-t "$SCENARIO_ID" \
-e "$STAGING_ENV_ID" \
-r cli,junit
Cùng một kịch bản, nhưng trỏ đến một giá trị -e khác, sẽ trở thành bài kiểm thử sơ bộ (smoke test) sản xuất của bạn. Không có gì về bài kiểm thử thay đổi; chỉ có môi trường mà nó giải quyết chống lại thay đổi. Lưu trữ APIDOG_ACCESS_TOKEN trong GitHub Secrets, các biến của GitLab CI/CD hoặc trình quản lý thông tin xác thực của runner của bạn, và tham chiếu nó bằng tên. Quy tắc rất đơn giản: bất cứ điều gì khác biệt giữa các môi trường hoặc bất cứ điều gì bí mật đều là cấu hình, và cấu hình được đưa vào trong thời gian chạy.
5. Đảm bảo các bài kiểm thử có tính xác định để pipeline đáng tin cậy
Một bài kiểm thử không ổn định (flaky test) là bài kiểm thử thất bại vì những lý do không liên quan đến mã của bạn. Đó cũng là cách nhanh nhất để phá hủy uy tín của một pipeline. Một khi một bộ kiểm thử "thỉnh thoảng thất bại", các nhà phát triển bắt đầu chạy lại các job cho đến khi chúng xanh, điều đó có nghĩa là một lỗi thực sự giờ đây bị che giấu bởi tiếng ồn của những lỗi giả.
Hầu hết sự không ổn định của kiểm thử API đến từ một vài nguồn có thể dự đoán được:
- Trạng thái có thể thay đổi được chia sẻ. Hai bài kiểm thử tạo một người dùng với cùng một email, hoặc một bài kiểm thử phụ thuộc vào dữ liệu mà bài kiểm thử khác đã xóa. Mỗi bài kiểm thử nên thiết lập và hủy bỏ dữ liệu của riêng nó, hoặc sử dụng các tenant bị cô lập.
- Giả định về thời gian. Xác nhận một kết quả bất đồng bộ trước khi nó sẵn sàng. Nếu một hoạt động cuối cùng sẽ xảy ra, hãy thăm dò điều kiện thay vì chờ một số giây cố định.
- Các phụ thuộc thực sự mà bạn không kiểm soát. Một sandbox thanh toán của bên thứ ba giới hạn tốc độ truy cập của bạn, hoặc một dịch vụ upstream đang ngừng hoạt động để bảo trì. Hãy mô phỏng (mock) các ranh giới đó để bài kiểm thử của bạn đo lường API của bạn, không phải thời gian hoạt động của người khác. Apidog có thể tạo một mock cho một phụ thuộc không ổn định từ schema của nó, giúp loại bỏ sự không ổn định bên ngoài khỏi bản dựng của bạn.
- Phụ thuộc vào thứ tự. Các bài kiểm thử chỉ vượt qua khi chạy theo một trình tự cụ thể. Một bộ kiểm thử nên vượt qua khi chạy theo bất kỳ thứ tự nào, bởi vì các runner sẽ chạy song song.
Tính xác định là sự khác biệt giữa một pipeline mà mọi người tôn trọng và một pipeline mà họ cố gắng tránh. Hãy đầu tư công sức vào nó từ sớm; các bài kiểm thử không ổn định sẽ tích lũy lỗi.
6. Giữ giai đoạn kiểm thử API nhanh chóng, nếu không các nhà phát triển sẽ bỏ qua nó
Một bộ kiểm thử mất hai mươi phút trên mỗi pull request sẽ trở thành một gánh nặng mà các nhà phát triển phẫn nộ và cuối cùng sẽ tắt. Tốc độ không phải là một điều "tốt nếu có" trong CI; đó là thứ giúp bộ kiểm thử chạy được. Mục tiêu mà hầu hết các nhóm hướng tới là giai đoạn kiểm thử API dưới năm phút trên các PR.
Một vài đòn bẩy giúp bạn đạt được điều đó:
- Chạy các kịch bản độc lập song song. Nếu các bài kiểm thử của bạn có tính xác định (thực hành tốt nhất thứ năm), không có gì ngăn cản bạn chia chúng ra các job song song hoặc để runner phân phối chúng. Các bộ kiểm thử độc lập có thể chạy cạnh nhau.
- Phân cấp các bài kiểm thử của bạn. Chạy một bộ kiểm thử sơ bộ nhanh trên mỗi PR và bộ kiểm thử hồi quy đầy đủ khi hợp nhất vào
mainhoặc theo lịch trình hàng đêm. Không phải mọi bài kiểm thử đều cần kiểm tra mọi commit. - Lưu vào bộ nhớ cache quá trình cài đặt. Lưu trữ bản cài đặt npm toàn cục của
apidog-cliqua các lần chạy sẽ rút ngắn thời gian thiết lập của mỗi job. - Báo lỗi nhanh khi có ích, hoàn thành khi không. Trên một PR, dừng lại ở lỗi đầu tiên để cung cấp phản hồi nhanh chóng. Trên một lần chạy đầy đủ hàng đêm, sử dụng cờ
--on-error continuecủa CLI để một endpoint bị hỏng không che giấu bốn mươi endpoint khác cũng bị hỏng.
Đây là mẫu phân cấp trong GitHub Actions, với một lần chạy sơ bộ nhanh trên các PR và bộ kiểm thử đầy đủ theo lịch trình:
name: Kiểm thử API
on:
pull_request:
branches: [main]
schedule:
- cron: '0 2 * * *' # hồi quy đầy đủ hàng đêm
jobs:
api-tests:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '20'
- run: npm install -g apidog-cli
- name: Chạy bộ kiểm thử
run: |
if [ "${{ github.event_name }}" = "pull_request" ]; then
apidog run --access-token "$APIDOG_ACCESS_TOKEN" -t "$SMOKE_ID" -e "$ENV_ID" -r cli,junit --out-dir ./test-results
else
apidog run --access-token "$APIDOG_ACCESS_TOKEN" -t "$FULL_ID" -e "$ENV_ID" -r cli,junit --on-error continue --out-dir ./test-results
fi
env:
APIDOG_ACCESS_TOKEN: ${{ secrets.APIDOG_ACCESS_TOKEN }}
Một giai đoạn nhanh chóng được chạy có giá trị hơn một giai đoạn kỹ lưỡng nhưng bị vô hiệu hóa.
7. Phát hành kết quả có thể đọc được bằng máy, không chỉ là một loạt văn bản trên console
Khi một bản dựng thất bại, "các bài kiểm thử API đã thất bại" là chưa đủ. Bạn cần biết xác nhận nào bị hỏng, trong kịch bản nào, trên yêu cầu nào. Một bản dựng đỏ với hàng nghìn dòng đầu ra console hầu như không tốt hơn việc không có kiểm thử nào cả; ai đó vẫn phải đọc nó.
Giải pháp là xuất kết quả theo định dạng mà máy chủ CI của bạn có thể phân tích cú pháp gốc. JUnit XML là định dạng kết quả kiểm thử CI tiêu chuẩn, và hầu hết mọi nền tảng đều đọc được nó. Apidog CLI ghi một tệp bằng bộ báo cáo junit:
apidog run \
--access-token "$APIDOG_ACCESS_TOKEN" \
-t "$SCENARIO_ID" \
-e "$ENV_ID" \
-r cli,html,junit \
--out-dir ./test-results
Lệnh đó xuất ra ba chế độ xem của cùng một lần chạy: cli cho đầu ra console trực tiếp, html cho một báo cáo có thể duyệt mà con người có thể mở và junit cho máy. Trỏ pipeline của bạn vào tệp XML và nền tảng sẽ biến nó thành các kết quả có cấu trúc, cho từng bài kiểm thử:
- name: Xuất báo cáo kiểm thử
if: always()
uses: actions/upload-artifact@v4
with:
name: kết-quả-kiểm-thử-api
path: ./test-results
Lưu ý if: always(). Bạn muốn báo cáo được xuất bản ngay cả khi lần chạy thất bại, bởi vì một lần chạy thất bại chính là lúc bạn cần nó nhất. Hiệu quả là thực tế: thay vì "bản dựng API bị lỗi", bạn nhận được "xác nhận cart-total trong kịch bản thanh toán bắt đầu thất bại", điều này biến một phiên gỡ lỗi thành một cái nhìn thoáng qua.
8. Kiểm soát việc hợp nhất dựa trên bộ kiểm thử bằng tính năng bảo vệ nhánh
Một bộ kiểm thử vượt qua mà không chặn bất cứ điều gì chỉ là một thông báo. Mục đích của CI là làm cho mã bị lỗi không thể hợp nhất được, và điều đó cần thêm một bước mà hầu hết các nhóm không cấu hình: bảo vệ nhánh.
Mã thoát thực hiện công việc cục bộ. Bởi vì Apidog CLI thoát với mã khác 0 khi có bất kỳ xác nhận nào thất bại, công việc sẽ báo lỗi bằng màu đỏ khi có lỗi thực sự. Nhưng một công việc đỏ trên PR chỉ là lời khuyên cho đến khi bạn biến kiểm tra đó thành bắt buộc. Trong GitHub, đặt kiểm tra API-tests là một kiểm tra trạng thái bắt buộc trên main; nút hợp nhất sẽ bị vô hiệu hóa cho đến khi nó xanh. GitLab và Bitbucket có tính năng tương đương trong cài đặt yêu cầu hợp nhất của họ.
Đây là sự khác biệt giữa một bộ kiểm thử bắt được các lỗi hồi quy và một bộ kiểm thử chỉ ghi lại chúng sau khi sự việc đã xảy ra. Nếu không có kiểm tra bắt buộc, một nhà phát triển dưới áp lực thời hạn sẽ nhấp vào hợp nhất và API bị lỗi sẽ được phát hành với một kiểm tra màu đỏ nằm ngay bên cạnh. Với cổng chặn, nền tảng sẽ từ chối. Bài kiểm thử không còn là một gợi ý mà trở thành một quy tắc mà công cụ sẽ thực thi cho bạn.
Kết hợp điều này với các kết quả có thể đọc được bằng máy từ thực hành tốt nhất thứ bảy và tích hợp trạng thái commit, máy chủ Git của bạn sẽ hiển thị chính xác kiểm tra thất bại ngay trên PR. Vòng lặp phản hồi đóng lại: đẩy, kiểm thử, bị chặn, sửa lỗi, xanh, hợp nhất.
9. Tạo vùng phủ kiểm thử từ đặc tả API của bạn thay vì viết thủ công
Phần chậm nhất của kiểm thử API là giữ cho các bài kiểm thử đồng bộ với API. Mỗi endpoint mới cần một bài kiểm thử mới; mỗi trường thay đổi cần một xác nhận được cập nhật. Nếu làm thủ công, các bài kiểm thử luôn đi sau API, và khoảng cách đó là nơi các lỗi hồi quy tồn tại.
Động thái tận dụng là điều khiển các bài kiểm thử từ hợp đồng. Nếu API của bạn có đặc tả OpenAPI, bạn có thể tạo khung kiểm thử từ đó: một yêu cầu cho mỗi endpoint, với schema đã mô tả hình dạng phản hồi mong đợi. Trong Apidog, đặc tả và các bài kiểm thử nằm trong cùng một không gian làm việc, vì vậy một kịch bản kiểm thử có thể được xây dựng trực tiếp từ các endpoint đã được ghi lại thay vì sao chép từ chúng. Chúng tôi trình bày quy trình tạo trong Cách tạo bộ sưu tập kiểm thử API từ các đặc tả OpenAPI.
Điều này quan trọng trong CI vì các bài kiểm thử dựa trên đặc tả bắt được một lỗi phổ biến, cụ thể: sự sai lệch giữa những gì tài liệu của bạn hứa hẹn và những gì API của bạn trả về. Khi bài kiểm thử được tạo từ đặc tả và chạy đối với API trực tiếp, một sự không khớp sẽ làm bản dựng thất bại. Hợp đồng trở thành có thể thực thi. Bạn vẫn viết các xác nhận mã hóa ý nghĩa kinh doanh bằng tay, nhưng bạn không phải viết thủ công các đoạn mã lặp lại của việc "endpoint này có tồn tại và trả về hình dạng được ghi lại hay không". Hãy để đặc tả gánh vác phần đó.
10. Sử dụng kiểm thử theo hướng dữ liệu để bao phủ các trường hợp biên mà không cần nhân đôi kịch bản
Cùng một endpoint có hành vi khác nhau tùy theo đầu vào: một đơn hàng hợp lệ, một đơn hàng vượt quá giới hạn tín dụng, một đơn hàng với SKU không xác định, một đơn hàng bằng đơn vị tiền tệ không được hỗ trợ. Viết một kịch bản riêng cho mỗi trường hợp là cách các bộ kiểm thử phình to thành hàng trăm bài kiểm thử gần như giống hệt nhau mà không ai duy trì.
Kiểm thử theo hướng dữ liệu chạy một kịch bản trên nhiều hàng dữ liệu đầu vào. Bạn định nghĩa yêu cầu và các xác nhận một lần, sau đó cung cấp một bảng các trường hợp. Apidog CLI chấp nhận một tệp dữ liệu với cờ -d:
apidog run \
--access-token "$APIDOG_ACCESS_TOKEN" \
-t "$SCENARIO_ID" \
-e "$ENV_ID" \
-d ./test-data/orders.csv \
-r cli,junit \
--out-dir ./test-results
Mỗi hàng trong orders.csv trở thành một lần lặp với kết quả pass hoặc fail riêng. Một kịch bản, một lần gọi CLI, vùng phủ các trường hợp biên đầy đủ và một báo cáo JUnit hiển thị các hàng đầu vào nào đã thất bại. Điều này giữ cho bộ kiểm thử của bạn nhỏ gọn và vùng phủ rộng, đó chính xác là sự đánh đổi bạn muốn trong CI. Hướng dẫn của chúng tôi về kiểm thử API theo hướng dữ liệu với CSV hoặc JSON đi sâu hơn vào việc cấu trúc tệp dữ liệu.
Mẫu này phát huy hiệu quả nhất trên logic xác thực và quy tắc giá cả, những nơi mà một endpoint duy nhất có nhiều nhánh nhất và nhiều cách nhất để âm thầm lỗi hồi quy.
11. Chạy kiểm thử sơ bộ sau triển khai (post-deploy smoke test) trên môi trường thực tế
Các bài kiểm thử vượt qua trên môi trường staging cho bạn biết bản dựng tốt. Chúng không cho bạn biết việc triển khai đã hoạt động. Lệch cấu hình, một biến môi trường bị thiếu, một bộ cân bằng tải bị định tuyến sai, một chứng chỉ hết hạn: tất cả những điều này đều vượt qua mọi kiểm thử trước khi hợp nhất và chỉ bị lỗi trong môi trường mà bạn thực sự đã triển khai đến.
Lá chắn là một bài kiểm thử sơ bộ (smoke test) chạy sau khi triển khai, chống lại mục tiêu trực tiếp. Đó là một bộ kiểm thử nhỏ, nhanh chóng, chỉ kiểm tra các đường dẫn quan trọng, luồng xác thực của bạn, các endpoint đọc và ghi quan trọng nhất của bạn, hướng đến môi trường sản xuất hoặc môi trường mới được triển khai. Bởi vì lệnh chạy có tính di động (thực hành tốt nhất thứ hai) và các môi trường chỉ là cấu hình (thực hành tốt nhất thứ tư), đây là cùng một bộ kiểm thử với một -e khác:
smoke-after-deploy:
needs: deploy
runs-on: ubuntu-latest
steps:
- uses: actions/setup-node@v4
with:
node-version: '20'
- run: npm install -g apidog-cli
- name: Kiểm thử sơ bộ sản xuất
run: |
apidog run \
--access-token "$APIDOG_ACCESS_TOKEN" \
-t "$SMOKE_SCENARIO_ID" \
-e "$PROD_ENV_ID" \
-r cli,junit \
--out-dir ./smoke-results
env:
APIDOG_ACCESS_TOKEN: ${{ secrets.APIDOG_ACCESS_TOKEN }}
Nếu bài kiểm thử sơ bộ thất bại, đó là tín hiệu để bạn quay lại phiên bản trước (roll back) trước khi người dùng nhận ra. Đối với các nhóm đang triển khai blue-green hoặc canary, bạn chạy bộ kiểm thử sơ bộ trên môi trường mới trước khi chuyển lưu lượng truy cập sang nó, để người dùng thực sự đầu tiên của bạn không bao giờ là người tìm thấy bản triển khai bị lỗi. Chi phí là một phút thời gian pipeline. Giải pháp thay thế là tìm ra lỗi từ một yêu cầu hỗ trợ.
12. Coi bộ kiểm thử như mã bạn duy trì, không phải là một thiết lập bạn hoàn thành
Thực hành tốt nhất cuối cùng là một tư duy. Một bộ kiểm thử CI không phải là một dự án bạn hoàn thành; nó là một tài sản bạn duy trì cùng với API mà nó bảo vệ. Các nhóm có pipeline đáng tin cậy là những nhóm coi một bài kiểm thử không ổn định như một lỗi, một giai đoạn chậm như nợ kỹ thuật, và một lỗ hổng trong vùng phủ là một lỗi hồi quy đang chờ xảy ra.
Một vài thói quen giúp duy trì một bộ kiểm thử lành mạnh về lâu dài:
- Thêm bài kiểm thử cùng với tính năng. Một endpoint mới được phát hành cùng với kịch bản của nó trong cùng một PR, không phải trong một PR theo sau mà không bao giờ được hợp nhất.
- Sửa lỗi không ổn định ngay khi chúng xuất hiện. Một bài kiểm thử không ổn định bị cách ly là một lỗ hổng vùng phủ với tín hiệu xanh. Đừng để
continue-on-errortrở thành vĩnh viễn. - Xem xét những gì bộ kiểm thử không bao phủ. Định kỳ kiểm tra xem những endpoint nào không có xác nhận. Những endpoint chưa được kiểm thử là nơi sự cố tiếp theo sẽ bắt đầu.
- Giữ cấu hình pipeline trong kiểm soát phiên bản. Tệp YAML của bạn, định nghĩa môi trường của bạn và dữ liệu kiểm thử của bạn đều nằm trong repo, được xem xét như bất kỳ thay đổi nào khác.
Bởi vì các định nghĩa kiểm thử nằm trong Apidog và pipeline chỉ chứa một lệnh gọi đơn giản, hầu hết việc bảo trì này diễn ra ở nơi dễ dàng: bạn thêm các kịch bản và xác nhận trong ứng dụng, và cấu hình CI hầu như không thay đổi. Các nhóm làm đúng điều này dành thời gian để cải thiện vùng phủ, chứ không phải mất công với YAML. Để có cái nhìn rộng hơn về việc tổ chức các bộ kiểm thử lớn, hãy xem Bộ kiểm thử Apidog: Một cách thông minh hơn để tự động hóa kiểm thử API.
Tổng hợp lại
Mười hai thực hành này củng cố lẫn nhau. Các lệnh chạy di động giúp kiểm thử sơ bộ sau triển khai trở nên đơn giản. Các bài kiểm thử có tính xác định làm cho việc chạy song song an toàn, giúp giai đoạn nhanh chóng, từ đó khuyến khích các nhà phát triển sử dụng nó. Kết quả có thể đọc được bằng máy làm cho tính năng bảo vệ nhánh trở nên có ý nghĩa, bởi vì cổng chặn chỉ vào một kiểm tra thất bại cụ thể thay vì một bức tường văn bản. Các bài kiểm thử dựa trên đặc tả và dựa trên dữ liệu giúp bộ kiểm thử toàn diện mà không làm chậm quá trình bảo trì.
Nền tảng chung là giữ các bài kiểm thử của bạn gần với hợp đồng của bạn và có thể chạy được từ một lệnh duy nhất. Đó là quy trình làm việc của Apidog gói gọn trong một câu: thiết kế API và các bài kiểm thử của nó tại một nơi, sau đó chạy chính xác bộ kiểm thử đó trong bất kỳ pipeline nào bằng lệnh apidog run. CLI thoát với mã khác 0 khi thất bại, xuất ra JUnit để CI của bạn phân tích cú pháp, và hoạt động như nhau cho dù GitHub Actions, GitLab, Jenkins, hay một runner tự host gọi nó.
Bắt đầu nhỏ. Kết nối một kịch bản quan trọng vào pipeline PR của bạn với các xác nhận thực tế và một kiểm tra trạng thái bắt buộc. Làm cho vòng lặp đó đáng tin cậy, sau đó thêm vào phần còn lại: các lần chạy theo tầng, các trường hợp biên dựa trên dữ liệu, một bài kiểm thử sơ bộ sau triển khai. Một pipeline mà bạn tin tưởng là một pipeline chỉ báo lỗi (màu đỏ) khi có điều gì đó thực sự bị hỏng, và chỉ báo thành công (màu xanh) khi việc phát hành thực sự an toàn. Tải xuống Apidog và xây dựng kịch bản đầu tiên ngay hôm nay.
Câu hỏi thường gặp
Sự khác biệt giữa kiểm thử API trong CI và CI/CD là gì? CI (tích hợp liên tục) chạy các bài kiểm thử API của bạn tự động trên mỗi commit hoặc pull request để phát hiện lỗi hồi quy sớm. CD (phân phối liên tục) quảng bá một bản dựng đến mục tiêu triển khai sau khi nó vượt qua các kiểm tra đó. Kiểm thử API tồn tại trong cả hai: một bộ kiểm thử trước khi hợp nhất (pre-merge suite) kiểm soát tích hợp, và một bộ kiểm thử sơ bộ sau triển khai (post-deploy smoke suite) xác minh việc phân phối. Cùng một lệnh Apidog CLI phục vụ cả hai giai đoạn.
Tôi có cần viết mã để chạy kiểm thử API trong pipeline không? Không. Bạn xây dựng các yêu cầu và xác nhận một cách trực quan trong Apidog, sau đó chạy chúng không giao diện (headlessly) chỉ với một lệnh apidog run. Pipeline chỉ cần lệnh đó, điều này giúp cấu hình CI của bạn gọn nhẹ và có nghĩa là các kỹ sư QA có thể quản lý các bài kiểm thử mà không cần duy trì một framework dựa trên mã. Hướng dẫn chi tiết có trong Cách tự động hóa kiểm thử API trong CI/CD.
Làm thế nào để các bài kiểm thử API của tôi không bị không ổn định (flaky) trong CI? Ba nguyên nhân lớn nhất là dữ liệu kiểm thử có thể thay đổi được chia sẻ, các giả định về thời gian trên các hoạt động bất đồng bộ và các phụ thuộc bên thứ ba không được kiểm soát. Cung cấp cho mỗi bài kiểm thử dữ liệu riêng của nó, thăm dò các điều kiện bất đồng bộ thay vì chờ một thời gian cố định và mô phỏng (mock) các ranh giới bên ngoài mà bạn không kiểm soát. Mục tiêu là một bộ kiểm thử vượt qua theo bất kỳ thứ tự nào và trong bất kỳ lần chạy nào.
Làm thế nào để một bài kiểm thử API thất bại chặn việc hợp nhất? Có hai phần. Thứ nhất, trình chạy kiểm thử phải thoát với mã khác 0 khi thất bại; Apidog CLI thực hiện điều này trên bất kỳ xác nhận nào thất bại, vì vậy công việc sẽ tự động báo lỗi bằng màu đỏ. Thứ hai, đánh dấu công việc đó là một kiểm tra trạng thái bắt buộc trong quy tắc bảo vệ nhánh của máy chủ Git của bạn. Nút hợp nhất sẽ bị vô hiệu hóa cho đến khi kiểm tra vượt qua.
Tôi có thể chạy cùng một bài kiểm thử API trong GitHub Actions, GitLab và Jenkins không? Có. Bởi vì logic kiểm thử nằm trong Apidog và pipeline chỉ gọi lệnh apidog run, lệnh này là giống hệt nhau trên các nhà cung cấp; chỉ có tệp YAML hoặc tập lệnh pipeline xung quanh thay đổi. Tính di động đó là điều khiến việc di chuyển nhà cung cấp CI chỉ là sửa sáu dòng thay vì viết lại. Xem Cách tự động hóa kiểm thử API trong GitHub Actions để biết thiết lập cụ thể cho GitHub.
Giai đoạn kiểm thử API của tôi nên nhanh đến mức nào? Hãy nhắm mục tiêu dưới năm phút cho các pull request. Đạt được điều đó bằng cách chạy một bộ kiểm thử sơ bộ nhanh trên các PR và bộ kiểm thử hồi quy đầy đủ hàng đêm, chạy song song các kịch bản độc lập và lưu vào bộ nhớ cache quá trình cài đặt CLI. Một giai đoạn chậm là một giai đoạn mà các nhà phát triển cuối cùng sẽ vô hiệu hóa, điều này làm mất đi mục đích.
