CYBERSOFT
Đăng nhập

PACT: Contract testing hướng consumer cho microservices

Chuyên công nghệContract/PACTAPINền tảng
🗓 1 tháng trước19 phút đọc·👁 1,090 lượt xem👤 311 người đọc

Vì sao E2E toàn phần tốn kém, cách Pact sinh hợp đồng từ consumer thật, viết interaction với PactV3, dùng matchers, đọc pact file và tránh cạm bẫy.

1. Bài toán tích hợp trong kiến trúc microservices

Hãy tưởng tượng một nền tảng fintech với hàng chục dịch vụ nhỏ: dịch vụ ví, dịch vụ thanh toán, dịch vụ hạn mức tín dụng, dịch vụ thông báo. Ứng dụng di động (consumer) gọi API của dịch vụ ví (provider) để lấy số dư. Mỗi dịch vụ do một đội khác nhau phát triển, deploy độc lập, nhiều lần mỗi ngày. Khi số lượng cặp gọi nhau tăng lên, một thay đổi nhỏ ở phía provider — đổi tên một trường JSON, bỏ một field, thay kiểu dữ liệu — có thể làm hỏng consumer mà không ai phát hiện cho tới khi khách hàng gặp lỗi trên production.

Câu hỏi cốt lõi mà mỗi đội phải trả lời trước khi deploy là: 'Thay đổi của tôi có phá vỡ bất kỳ ai đang phụ thuộc vào tôi không?'. Trong một hệ thống nguyên khối (monolith), trình biên dịch và bộ test tích hợp trong cùng một repo trả lời câu hỏi này ngay lập tức. Nhưng trong microservices, consumer và provider nằm ở hai repo, hai pipeline, hai vòng đời khác nhau. Không có trình biên dịch nào bắc cầu qua ranh giới mạng. Đây chính là khoảng trống mà contract testing (kiểm thử hợp đồng) và cụ thể là Pact ra đời để lấp đầy.

Oracle (nguồn phán xử) của contract testing không phải 'ứng dụng chạy đúng' mà là 'consumer và provider vẫn tương thích với nhau'. Đó là một oracle về khả năng tương thích, hẹp nhưng cực kỳ chính xác.

2. Vì sao contract testing thắng E2E toàn phần cho microservices

Cách phòng thủ truyền thống là dựng một môi trường staging đầy đủ, triển khai tất cả các dịch vụ thật, rồi chạy một bộ test đầu-cuối (E2E) đi qua toàn bộ hệ thống. Cách này có vẻ chắc chắn nhưng đắt và giòn. Để test tương tác giữa ví và thanh toán, bạn phải khởi động cả hai dịch vụ, cùng cơ sở dữ liệu, hàng đợi tin nhắn và mọi phụ thuộc. Với hàng chục dịch vụ, một môi trường như thế mất nhiều giờ để dựng, dễ hỏng vì lý do không liên quan, và khi test đỏ bạn không biết dịch vụ nào có lỗi.

Contract testing đảo ngược bài toán. Thay vì chạy hai dịch vụ thật cùng lúc, ta tách phép kiểm thành hai nửa độc lập. Nửa consumer chạy consumer thật đối diện với một provider giả lập (mock provider), ghi lại chính xác các yêu cầu mà consumer gửi và phản hồi mà nó mong đợi. Nửa provider chạy provider thật và phát lại đúng những yêu cầu đó, kiểm rằng provider trả về phản hồi khớp. Không lúc nào ta cần cả hai dịch vụ cùng chạy. Mỗi nửa nhanh như unit test, chạy được trong pipeline riêng của từng đội, và khi đỏ nó chỉ đúng một điểm hỏng: hợp đồng bị phá.

E2E toàn phần vs Contract testing Full E2E (đắt, giòn) Consumer Provider DB + MQ tất cả chạy cùng lúc · nhiều giờ đỏ → không rõ ai lỗi Contract (nhanh, chính xác) Consumer+ mock Provider+ replay pact file tách rời · vài giây mỗi nửa đỏ → biết đúng điểm hỏng
Contract testing tách phép kiểm thành hai nửa độc lập, kết nối qua một pact file thay vì môi trường chung.
  • Phản hồi nhanh: mỗi nửa chạy trong vài giây, không cần dựng cả hệ thống.
  • Định vị lỗi chính xác: test đỏ chỉ đúng một cặp consumer-provider.
  • Độc lập vòng đời: mỗi đội chạy phần của mình trong pipeline riêng.
  • Consumer-driven: hợp đồng phản ánh đúng những gì consumer thực sự dùng.
⚠️ Contract testing KHÔNG thay thế mọi loại test. Nó không kiểm logic nghiệp vụ sâu, hiệu năng, hay hành trình người dùng phức tạp. Nó chỉ bảo vệ một thứ: sự tương thích của giao diện giữa hai dịch vụ. Hãy dùng nó cùng unit test và một lượng nhỏ E2E cho các luồng quan trọng nhất.

3. Pact hoạt động thế nào: hợp đồng do consumer sinh ra

Điểm khác biệt then chốt của Pact so với các cách tiếp cận khác nằm ở hai chữ 'consumer-driven' (do consumer dẫn dắt). Hợp đồng không được viết trước bởi kiến trúc sư rồi áp xuống. Thay vào đó, chính consumer, thông qua bài test của nó, tuyên bố: 'Tôi sẽ gửi yêu cầu này và tôi cần phản hồi có hình dạng này'. Khi bài test consumer chạy, thư viện Pact khởi động một mock provider trong bộ nhớ, consumer thật gọi vào mock đó, và Pact ghi lại mọi tương tác (interaction) thành một file JSON gọi là pact file.

Pact file này là hiện vật trung tâm của toàn bộ quy trình. Nó chứa danh sách các interaction, mỗi interaction gồm: một provider state (trạng thái tiên quyết mà provider cần có), một request (method, path, headers, body mong đợi) và một response (status, headers, body mà consumer sẽ nhận và xử lý được). Vì được sinh từ chính consumer thật đang chạy, hợp đồng luôn phản ánh đúng thực tế sử dụng, không bao giờ lệch pha với code. Sau đó pact file được chuyển sang phía provider để phát lại — đó là bước provider verification (kiểm chứng provider) mà bài tiếp theo sẽ đi sâu.

🔒

Nội dung bị khoá

Bạn đang xem bản xem trước. Đăng nhập để mở khoá toàn bộ bài viết và tất cả tài liệu Tester/QA.

Đã xem 24% nội dung
  • Đọc trọn vẹn mọi bài viết
  • Lưu bài & ghi chú cá nhân
  • Theo dõi tiến độ đã đọc
  • Luyện phỏng vấn, ISTQB, Mock
Đăng nhập để đọc tiếp

Chưa có mã? Lấy mã qua Fanpage / Zalo CyberSoft.

0

💬 Bình luận (0)

Bạn có thể đọc mọi bình luận. Đăng nhập để bình luận

Chưa có bình luận nào. Hãy là người đầu tiên!