Tavern là một công cụ kỹ thuật thông minh. Nó tích hợp vào pytest, cho phép bạn mô tả một bài kiểm thử API dưới dạng tệp YAML và chạy tệp đó như một bài kiểm thử pytest thông thường. Bạn nhận được toàn bộ hệ sinh thái của pytest miễn phí: fixtures, plugin, chạy song song với pytest-xdist, báo cáo độ bao phủ mã, cùng một lệnh mà nhóm Python của bạn đã sử dụng. Đối với một nhóm backend chuyên dùng pytest, việc viết thêm một tệp test_*.tavern.yaml bên cạnh các bài kiểm thử đơn vị cảm thấy rất tự nhiên.
Sự bất tiện xuất hiện khi tệp YAML lớn dần. Một yêu cầu duy nhất gửi một body, lưu một token và kiểm tra một vài trường phản hồi sẽ biến thành một khối lồng ghép các khóa request, response, save và verify_response_with mà bạn phải thụt lề chính xác. Các luồng nhiều giai đoạn (đăng nhập, tạo tài nguyên, đọc lại, xóa) chồng chất các khối đó thành một tệp dài nơi một khoảng trắng sai vị trí sẽ làm hỏng quá trình phân tích cú pháp và hợp đồng API mà bài kiểm thử xác minh lại nằm ở một nơi hoàn toàn khác: một tệp Swagger, một trang wiki, một bộ sưu tập Postman đã lỗi thời từ nhiều tháng trước.
Những điểm mạnh của Tavern
Hãy bắt đầu với những điểm cộng, vì Tavern xứng đáng được khen ngợi.
Nó dựa trên pytest thay vì thay thế pytest. Tavern là một plugin của pytest. Bạn cài đặt nó bằng pip install tavern, thả một tệp YAML vào thư mục kiểm thử của mình, và pytest sẽ tìm thấy và chạy nó như bất kỳ bài kiểm thử nào khác. Điều đó có nghĩa là bạn giữ lại mọi thói quen pytest mà nhóm của bạn đã có: -k để lọc, -x để dừng khi gặp lỗi đầu tiên, pytest-html cho báo cáo, pytest-xdist cho các lần chạy song song, fixtures cho việc thiết lập chung. Không có gì thay đổi về trình chạy của bạn. Đối với một công ty Python, đó là một lợi thế thực sự, và rất ít công cụ kiểm thử API tích hợp gọn gàng như vậy với một bộ công cụ hiện có.
YAML mang tính khai báo và dễ đọc. Một bài kiểm thử Tavern đơn giản thực sự dễ dàng xem qua:
test_name: Get a single order
stages:
- name: Fetch order 1042
request:
url: https://api.shop.test/orders/1042
method: GET
response:
status_code: 200
json:
id: 1042
status: shipped
Không có mã kết nối, không có thư viện xác nhận để nhập, không có công cụ kiểm thử để viết. Yêu cầu và phản hồi mong đợi nằm cạnh nhau. Để kiểm tra mã trạng thái và một vài trường, cách này dễ đọc hơn so với mã Python tương đương sử dụng requests cộng với assert.
Lưu và nối biến. Tavern có thể lấy một giá trị từ một phản hồi và đưa nó vào giai đoạn tiếp theo bằng cách sử dụng save và thay thế {variable}, do đó một luồng đăng nhập-sau-đó-gọi hoạt động mà không cần mã tùy chỉnh:
stages:
- name: Log in
request:
url: https://api.shop.test/auth/login
method: POST
json:
username: tester
password: hunter2
response:
status_code: 200
save:
json:
token: access_token
- name: Read the profile with the saved token
request:
url: https://api.shop.test/me
method: GET
headers:
Authorization: "Bearer {token}"
response:
status_code: 200
Nó làm được nhiều hơn HTTP. Tavern cũng kiểm tra MQTT, điều này quan trọng nếu bạn làm việc với IoT hoặc các hệ thống hướng thông điệp. Và vì nó dựa trên pytest, bạn có thể kết hợp các bài kiểm tra API YAML và các bài kiểm tra Python thông thường trong cùng một lần chạy và cùng một báo cáo.
Không có điều nào trong số đó là quảng cáo. Tavern là một công cụ vững chắc. Câu hỏi là liệu những giả định của nó có phù hợp với bạn hay không.
Nơi các mã YAML lặp lại chồng chất
Ba chi phí đi kèm với mô hình của Tavern, và liệu chúng có quan trọng hay không tùy thuộc vào quy mô bộ kiểm thử của bạn.
YAML nhạy cảm với khoảng trắng và lược đồ rất sâu. Ví dụ đơn giản ở trên trông gọn gàng. Một bài kiểm thử thực tế thì không. Khi bạn thêm headers, query parameters, một request body, các xác nhận body phản hồi, kiểm tra kiểu dữ liệu, các biến đã lưu và các hàm bên ngoài verify_response_with, bạn sẽ lồng ghép sâu bốn đến năm cấp trong một định dạng mà một khoảng trắng sai chỗ sẽ gây ra lỗi phân tích cú pháp, chứ không phải một thông báo rõ ràng. Các trình soạn thảo không tự động hoàn thành các khóa của Tavern theo cách một IDE tự động hoàn thành một phương thức Python, vì vậy bạn phải kiểm tra tài liệu để biết liệu đó là status_code hay status, json hay body cho mỗi trường mới.
Bài kiểm thử và hợp đồng API là hai thành phần riêng biệt. YAML của Tavern của bạn mã hóa cứng URL, phương thức, các trường mong đợi và kiểu dữ liệu của chúng. Định nghĩa API thực tế nằm trong một tệp OpenAPI, các trình trang trí route của một framework, hoặc không ai chắc chắn ở đâu. Khi API thay đổi tên trường, không có gì thông báo cho YAML. Bài kiểm thử tiếp tục xác nhận hình dạng cũ cho đến khi nó thất bại trong CI hoặc, tệ hơn, tiếp tục vượt qua với một kỳ vọng lỗi thời. Ai đó phải giữ cho hai thứ này đồng bộ hóa thủ công, và người đó thường là người phải đối mặt với lỗi lúc 2 giờ sáng.
Nó giả định một chuỗi công cụ Python và những người dùng Python. Tavern rất tuyệt nếu những người kiểm thử của bạn viết Python. Nếu nhóm QA, kỹ sư frontend hoặc những người làm sản phẩm của bạn muốn thêm hoặc đọc một bài kiểm thử, họ phải đối mặt với pip, virtualenvs, các quy ước của pytest và các quy tắc lược đồ YAML cùng một lúc chỉ để gửi một yêu cầu HTTP và kiểm tra phản hồi. Ngưỡng gia nhập rất cao đối với bất kỳ ai không thuộc thế giới Python.
Đường dẫn bỏ qua YAML
Giải pháp thay thế là ngừng tạo các bài kiểm thử dưới dạng tệp văn bản và bắt đầu xây dựng chúng dựa trên định nghĩa API mà bạn đã có.
Trong Apidog, đặc tả API, yêu cầu và bài kiểm thử là cùng một đối tượng. Bạn nhập hoặc thiết kế API của mình một lần (OpenAPI, Swagger, hoặc một bộ sưu tập Postman có thể nhập chỉ bằng một cú nhấp), và mỗi endpoint mang theo lược đồ thực của nó. Bạn xây dựng một kịch bản kiểm thử bằng cách xâu chuỗi các endpoint đó một cách trực quan: kéo cuộc gọi đăng nhập vào, kéo cuộc gọi cần token vào, và chuyển giá trị đi mà không cần viết các khối save: hoặc chuỗi {variable} bằng tay. Các xác nhận là các ô chọn và biểu thức trong một bảng điều khiển, chứ không phải là các khóa YAML thụt lề mà bạn phải nhớ.
Bởi vì bài kiểm thử được xây dựng dựa trên đặc tả, đặc tả là nguồn chân lý duy nhất. Thay đổi một trường phản hồi trong thiết kế và các kịch bản kiểm thử tham chiếu đến nó sẽ hiển thị sự thay đổi thay vì âm thầm bị trôi dạt. Đó là phần mà Tavern về cấu trúc không thể làm được: YAML của nó không có liên kết ngược lại với hợp đồng.
Và khi đến lúc tự động hóa, bạn không mất đi tính chất không giao diện người dùng (headless), thân thiện với CI đã làm cho Tavern trở nên hấp dẫn. Apidog CLI chạy các kịch bản tương tự từ dòng lệnh, trong CI, không có giao diện người dùng, giống hệt cách pytest chạy các tệp Tavern của bạn hiện nay.
Cài đặt và chạy Apidog CLI
Trình chạy là một gói npm miễn phí có tên apidog-cli. Cài đặt nó trên toàn cầu:
npm install -g apidog-cli
Sau đó chạy một kịch bản kiểm thử với lệnh apidog run:
apidog run --access-token $APIDOG_ACCESS_TOKEN -t 605067 -e 1629989 -r cli
Đây là ý nghĩa của từng phần:
--access-tokenxác thực lần chạy với tài khoản Apidog của bạn. Tạo token từ tab CI/CD của kịch bản và lưu trữ nó dưới dạng bí mật, không bao giờ trong tệp.-tlà ID kịch bản kiểm thử.-elà ID môi trường (dev, staging, prod), để cùng một kịch bản truy cập đúng URL cơ sở và biến số.-rchọn các trình báo cáo (reporters).cliin kết quả dễ đọc ra terminal.
Bạn không cần phải ghi nhớ các ID đó. Mở kịch bản kiểm thử trong Apidog, chuyển đến tab CI/CD của nó, chọn tùy chọn dòng lệnh và nhấp vào "Generate token". Apidog sẽ tạo lệnh apidog run hoàn chỉnh cho bạn với ID kịch bản và ID môi trường đã được điền sẵn. Sao chép nó, sau đó di chuyển token vào một bí mật CI.
Nếu bạn không muốn cài đặt toàn cục, đặc biệt trên một trình chạy CI tạm thời, hãy chạy nó bằng npx:
npx apidog-cli run --access-token $APIDOG_ACCESS_TOKEN -t 605067 -e 1629989 -r cli
Các trình báo cáo bao gồm cli, html, json và junit. Đối với CI, sự kết hợp hữu ích là -r html,junit: junit xuất ra XML tiêu chuẩn mà hầu hết các bảng điều khiển CI phân tích thành cây pass/fail, và html tạo ra một báo cáo có thể duyệt được mà bạn có thể lưu trữ như một build artifact. Thêm --out-dir để kiểm soát nơi chúng được lưu:
apidog run --access-token $APIDOG_ACCESS_TOKEN -t 605067 -e 1629989 -r html,junit --out-dir ./apidog-reports
Để biết danh sách đầy đủ các cờ trên phiên bản đã cài đặt của bạn, hãy chạy apidog run --help.
So sánh
| Tavern | Apidog | |
|---|---|---|
| Định dạng kiểm thử | Tệp YAML (*.tavern.yaml) |
Các kịch bản trực quan được xây dựng dựa trên đặc tả |
| Môi trường chạy | Python + pytest | Chạy không giao diện apidog run (gói npm) |
| Cách tạo | Viết tay và thụt lề YAML | Kéo và nối các endpoint, xác nhận bằng ô chọn |
| Hợp đồng API | Thành phần riêng biệt, được đồng bộ thủ công | Đặc tả là nguồn chân lý cho bài kiểm thử |
| Nối biến | Các khối save: và thay thế {var} |
Truyền giá trị giữa các bước trong giao diện người dùng |
| Trình báo cáo | pytest-html, JUnit qua các plugin pytest |
cli, html, json, junit tích hợp sẵn |
| Ai có thể viết kiểm thử | Người kiểm thử thoải mái với Python | Bất kỳ ai trong nhóm, bao gồm cả những người không lập trình |
| Giao thức | HTTP và MQTT | HTTP, cộng với SOAP, WebSocket, gRPC, và nhiều hơn nữa |
Tavern sẽ chiếm ưu thế nếu nhóm của bạn hoàn toàn sử dụng Python và bạn muốn các bài kiểm thử nằm trong cùng một kho lưu trữ và cùng một lần chạy pytest với các bài kiểm thử đơn vị của bạn. Apidog sẽ chiếm ưu thế nếu bạn muốn loại bỏ việc bảo trì YAML, giữ hợp đồng và bài kiểm thử là một, và cho phép những người không viết Python đóng góp các bài kiểm thử.
Tích hợp vào CI
Việc chạy không giao diện (headless run) là toàn bộ ý nghĩa của việc chuyển từ một tệp kiểm thử cục bộ sang một pipeline. Đây là cấu trúc của GitHub Actions:
name: API tests
on: [push, pull_request]
jobs:
api-tests:
runs-on: ubuntu-latest
steps:
- name: Install Apidog CLI
run: npm install -g apidog-cli
- name: Run API test scenario
run: |
apidog run \
--access-token "$APIDOG_ACCESS_TOKEN" \
-t 605067 \
-e 1629989 \
-r html,junit \
--out-dir apidog-reports
env:
APIDOG_ACCESS_TOKEN: ${{ secrets.APIDOG_ACCESS_TOKEN }}
- name: Upload report
if: always()
uses: actions/upload-artifact@v4
with:
name: apidog-report
path: apidog-reports
Token đến từ các bí mật của kho lưu trữ và được truyền đến bước dưới dạng biến môi trường. if: always() trên bước tải lên có nghĩa là bạn vẫn nhận được báo cáo khi các bài kiểm thử thất bại, đó chính là lúc bạn muốn đọc nó. Nếu một xác nhận thất bại, bước apidog run sẽ thoát với mã lỗi khác 0, công việc chuyển sang màu đỏ và yêu cầu kéo sẽ hiển thị một kiểm tra thất bại.
Hành vi mã thoát đó là cổng chất lượng, và nó hoạt động giống như của Tavern: CI đọc mã thoát của mỗi bước, mã thoát khác 0 sẽ làm thất bại công việc, và một công việc thất bại sẽ chặn việc hợp nhất hoặc triển khai. Bạn không cần cấu hình thêm bất kỳ điều gì. Đối với các thiết lập pipeline sâu hơn, Apidog CLI trong pipeline CI/CD của bạn và hướng dẫn GitHub Actions cũng bao gồm các biến thể GitLab CI và Jenkins.
Lưu ý về pytest và thế giới kiểm thử Python rộng lớn hơn
Việc không sử dụng YAML của Tavern không có nghĩa là từ bỏ pytest. Rất nhiều nhóm giữ các bài kiểm thử đơn vị và tích hợp Python thuần túy của họ trong pytest và sử dụng Apidog cho lớp hợp đồng API, phần mà bài kiểm thử nên theo dõi đặc tả và cũng có thể chạy cho những người không đóng góp bằng Python. Hai điều này không loại trừ lẫn nhau. Giá trị của Tavern luôn là cho phép những người dùng pytest viết các bài kiểm thử API ở định dạng nhẹ hơn so với mã requests thô; giá trị của Apidog là làm cho các bài kiểm thử API đó theo dõi hợp đồng và giữ được khả năng đọc khi bộ kiểm thử phát triển vượt qua một vài tệp.
Nếu bạn cũng đang cân nhắc các trình chạy khác, logic tương tự cũng áp dụng cho câu chuyện dòng lệnh của Postman trong Postman CLI vs Newman và cho việc chạy các bộ sưu tập mà không cần công cụ bổ sung trong Kiểm thử API không cần Postman.
Câu hỏi thường gặp
Apidog CLI có miễn phí không? Có. Gói npm apidog-cli miễn phí để cài đặt và chạy bằng npm install -g apidog-cli. Nó thực thi các kịch bản kiểm thử từ dự án Apidog của bạn, vì vậy những gì bạn có thể chạy phụ thuộc vào gói Apidog của bạn, nhưng bản thân trình chạy dòng lệnh không phải là một sản phẩm trả phí riêng biệt.
Tôi có thể sử dụng pytest cùng với Apidog không? Có. Hãy giữ các bài kiểm thử đơn vị và tích hợp Python của bạn trong pytest và sử dụng Apidog cho lớp kiểm thử hợp đồng API. Nhiều nhóm chạy cả hai. Sự khác biệt là các bài kiểm thử Apidog theo dõi đặc tả thay vì mã hóa cứng nó trong một tệp riêng biệt.
Apidog chặn một lần hợp nhất kém trong CI như thế nào? Thông qua mã thoát. Khi bất kỳ xác nhận nào thất bại, apidog run sẽ thoát với mã lỗi khác 0. CI đọc mã thoát đó, đánh dấu bước là thất bại và chặn việc hợp nhất hoặc triển khai. Bạn không cần cấu hình thêm bất kỳ điều gì để điều này hoạt động.
Tôi nên sử dụng trình báo cáo nào cho CI? Sử dụng junit cho kết quả mà máy có thể đọc được để bảng điều khiển CI của bạn phân tích thành cây pass/fail, và thêm html nếu bạn muốn một báo cáo có thể duyệt được lưu trữ dưới dạng artifact. Một lựa chọn phổ biến là -r html,junit, với cli được bật để có kết quả nhật ký build dễ đọc.
Apidog chỉ kiểm tra HTTP, giống như chế độ HTTP của Tavern? Không. Apidog hỗ trợ HTTP cộng với SOAP, WebSocket, Server-Sent Events và gRPC. Tavern bổ sung MQTT vào HTTP, đây là một điểm mà phạm vi giao thức của nó vượt trội hơn Apidog, vì vậy hãy lưu ý điều đó nếu MQTT là trọng tâm trong stack của bạn.
Bài học rút ra thẳng thắn
Tavern là một cách sạch sẽ để viết các bài kiểm thử API nếu bạn đã quen thuộc với pytest và YAML, và việc tích hợp pytest thực sự là tính năng tốt nhất của nó. Chi phí là bản thân YAML: nó trở nên sâu và dễ vỡ khi bộ kiểm thử mở rộng, và nó không có liên kết ngược lại với hợp đồng API mà nó xác minh. Nếu bạn muốn hành vi chạy không giao diện (headless), báo lỗi lớn trong CI tương tự mà không cần thụt lề YAML bằng tay và không cần duy trì một bản sao thứ hai của đặc tả của bạn, thì việc xây dựng các bài kiểm thử dựa trên hợp đồng và chạy chúng bằng apidog run là con đường nhẹ nhàng hơn.
Tải xuống Apidog và nhập một API hiện có để trải nghiệm quy trình làm việc 'đặc tả là kiểm thử' trước khi bạn cam kết. Bắt đầu miễn phí.
