Nếu bạn viết kiểm thử frontend, có lẽ bạn đã dùng hoặc nghe đến Mock Service Worker (MSW). MSW rất mạnh để chặn request trong trình duyệt và Node, đặc biệt cho unit test và component test. Bài viết này đi thẳng vào cách dùng MSW hiệu quả, giới hạn khi mock cần mở rộng cho nhiều đội/ngôn ngữ, và khi nào nên bổ sung một nền tảng tạo mock API được lưu trữ.
Mock Service Worker là gì?
Mock Service Worker là thư viện JavaScript dùng để chặn request mạng tại nguồn.
- Trong trình duyệt, MSW đăng ký một Service Worker để bắt
fetchvàXMLHttpRequest. - Trong Node, MSW vá lớp request để cùng một bộ handler có thể chạy trong Jest, Vitest hoặc môi trường test Node.
- Bạn định nghĩa handler theo method và path, sau đó trả về response mong muốn.
Điểm mạnh của MSW là ứng dụng vẫn gọi API như thật. Bạn không cần stub fetch, không cần thay đổi HTTP client, và không cần viết nhánh logic riêng cho môi trường test. MSW đứng giữa request và network để trả response mock.
Bạn có thể xem thêm mã nguồn MSW trên GitHub để hiểu cách lớp chặn hoạt động.
Ví dụ handler cơ bản:
import { http, HttpResponse } from 'msw'
export const handlers = [
http.get('/api/users/:id', ({ params }) => {
return HttpResponse.json({
id: params.id,
name: 'Ada Lovelace',
})
}),
]
Sau đó dùng handler này trong test hoặc môi trường dev. Mock nằm cạnh code, được version control cùng test, và chạy ở bất cứ nơi nào JavaScript chạy.
Khi nào nên dùng MSW?
MSW phù hợp nhất khi mock và code tiêu thụ mock nằm trong cùng một codebase.
1. Unit test và component test
Bạn render component, để component gọi API thật qua fetch hoặc HTTP client, rồi MSW trả dữ liệu mẫu.
Ví dụ với React Testing Library:
import { render, screen } from '@testing-library/react'
import { http, HttpResponse } from 'msw'
import { setupServer } from 'msw/node'
import UserProfile from './UserProfile'
const server = setupServer(
http.get('/api/users/:id', () => {
return HttpResponse.json({
id: '1',
name: 'Ada Lovelace',
})
})
)
beforeAll(() => server.listen())
afterEach(() => server.resetHandlers())
afterAll(() => server.close())
test('hiển thị tên người dùng', async () => {
render(<UserProfile userId="1" />)
expect(await screen.findByText('Ada Lovelace')).toBeInTheDocument()
})
Cách này khác với việc mock trực tiếp HTTP client. Nếu bạn đang so sánh hai hướng tiếp cận, xem thêm bài về cách mock một lệnh gọi API trong Jest.
2. Phát triển frontend khi backend chưa sẵn sàng
Bạn có thể dựng UI trước, sau đó đổi handler để mô phỏng nhiều trạng thái:
http.get('/api/orders', () => {
return HttpResponse.json([
{ id: 'ord_1', status: 'paid', total: 120 },
{ id: 'ord_2', status: 'pending', total: 80 },
])
})
Mô phỏng lỗi:
http.get('/api/orders', () => {
return new HttpResponse(null, { status: 500 })
})
Mô phỏng trạng thái rỗng:
http.get('/api/orders', () => {
return HttpResponse.json([])
})
3. CI ổn định hơn
Test không gọi server thật, nên ít bị ảnh hưởng bởi:
- network không ổn định
- dữ liệu staging thay đổi
- môi trường backend bị deploy lại
- rate limit hoặc auth token hết hạn
4. Một ngôn ngữ, một đội, một repository
Nếu đội viết mock cũng là đội tiêu thụ mock, giữ handler MSW trong repo là cách đơn giản và hiệu quả nhất.
Khi MSW bắt đầu gặp giới hạn
Điểm mạnh của MSW là mock sống trong codebase. Nhưng khi mock cần được chia sẻ rộng hơn, chính điều này lại thành giới hạn.
Người tiêu thụ không dùng JavaScript
Handler của MSW là JavaScript. Nếu mobile app viết bằng Swift/Kotlin, hoặc backend integration test chạy bằng Go/Python, các đội đó không thể import handler MSW của frontend.
Khi đó, bạn thường phải viết lại mock ở từng stack. Điều này dễ làm response giữa các môi trường bị lệch nhau.
Một máy chủ mock không phụ thuộc ngôn ngữ giải quyết vấn đề này bằng cách cung cấp URL HTTP thật. Bất kỳ client nào gọi được HTTP đều dùng được mock.
Cần một URL mock dùng chung
MSW chạy trong một process cụ thể:
- trong tab trình duyệt
- trong test runner
- trong dev server local
Nó không cung cấp một URL ổn định để QA, designer, mobile developer hoặc đối tác bên ngoài cùng truy cập.
Nếu nhiều người cần gọi cùng một endpoint mock, bạn cần một mock server được lưu trữ thay vì Service Worker gắn với môi trường local.
API được thiết kế từ OpenAPI/schema
Nếu đội bạn làm API design-first, bạn thường muốn:
- viết hoặc import OpenAPI schema
- sinh mock từ schema
- dùng mock để frontend/mobile phát triển song song
- đảm bảo mock không lệch hợp đồng API
MSW không tự sinh handler từ OpenAPI theo mặc định. Bạn phải tự viết handler. Cách này linh hoạt, nhưng cũng dễ khiến mock không còn khớp contract.
Bạn có thể xem thêm về hướng tiếp cận schema-first trong bài tạo mock API.
Cần dữ liệu động và thực tế ở quy mô lớn
Với MSW, response là thứ bạn tự code.
Ví dụ:
http.get('/api/users', () => {
return HttpResponse.json([
{
id: '1',
email: 'ada@example.com',
createdAt: '2026-06-01T10:00:00Z',
},
])
})
Cách này ổn cho vài endpoint. Nhưng khi API có nhiều resource, nhiều field, nhiều trạng thái biên, bạn sẽ phải tự duy trì nhiều dữ liệu mẫu.
Các nền tảng mock API thường có khả năng sinh dữ liệu theo tên field, kiểu dữ liệu hoặc schema, giúp giảm công viết dữ liệu thủ công.
MSW so với nền tảng tạo mock API đầy đủ
Không có lựa chọn nào “tốt hơn” trong mọi trường hợp. MSW và nền tảng mock API giải quyết hai bài toán khác nhau.
| Khả năng | Mock Service Worker | Nền tảng API được lưu trữ, ví dụ Apidog |
|---|---|---|
| Chạy trong unit/component test JS | Có, nguyên bản | Không, không phải thư viện test JS |
| Không phụ thuộc ngôn ngữ qua HTTP | Không, chủ yếu cho JS | Có, bất kỳ HTTP client nào |
| URL dùng chung cho toàn đội | Không | Có, mock server được lưu trữ |
| Tạo mock từ OpenAPI | Thủ công | Tự động từ schema |
| Dữ liệu thông minh/động | Tự code | Tích hợp sẵn |
| Sống trong repo cùng test | Có | Lưu trong project chia sẻ |
| Chi phí | Miễn phí, mã nguồn mở | Có gói miễn phí và gói trả phí |
Tóm lại:
- Dùng MSW cho unit test, component test và frontend local development.
- Dùng nền tảng như Apidog khi mock cần được chia sẻ, không phụ thuộc ngôn ngữ hoặc sinh từ API schema.
Apidog là phần bổ sung, không phải thay thế trực tiếp cho MSW
Apidog không phải là thư viện JavaScript để import vào Jest hoặc Vitest. Vì vậy, nó không thay thế MSW trong unit test.
Thay vào đó, Apidog phù hợp với lớp mock dùng chung cho cả đội.
Một workflow thực tế:
- Thiết kế hoặc import API schema vào Apidog.
- Tạo mock endpoint từ schema.
- Chia sẻ URL mock cho frontend, mobile, QA hoặc backend.
- Dùng response mock để phát triển song song trước khi backend hoàn thiện.
- Tùy chỉnh rule cho các case như
500, dữ liệu rỗng hoặc edge case cụ thể.
Ví dụ phân chia trách nhiệm:
Frontend unit/component test
↓
MSW
Cross-team mock / mobile / QA / demo
↓
Hosted mock server từ Apidog
Khi mock được tạo từ cùng schema với thiết kế và test API, bạn giảm rủi ro response mock bị lệch contract. Đây là điểm mà handler viết tay khó đảm bảo nếu dự án lớn dần.
Nếu muốn so sánh thêm các lựa chọn, xem bài tổng hợp các công cụ tạo mock API tốt nhất.
Một cách triển khai thực tế cho đội frontend:
- Giữ MSW trong repo frontend để test component.
- Dùng mock được lưu trữ cho mobile, QA, demo và tích hợp đa nhóm.
- Khi OpenAPI schema thay đổi, cập nhật mock server để các đội cùng dùng contract mới.
- Chỉ viết handler MSW cho các case test cụ thể, không cố duy trì toàn bộ API giả lập trong frontend repo.
Bạn có thể tải Apidog để thử song song với setup MSW hiện có.
Các lựa chọn thay thế MSW đáng biết
MSW không phải lựa chọn duy nhất. Tùy stack và mục tiêu, bạn có thể cân nhắc:
- Mockoon: ứng dụng desktop để tạo mock server local nhanh bằng GUI.
- WireMock: mock server dựa trên Java, phù hợp với đội JVM và contract testing.
- Prism của Stoplight: tạo mock trực tiếp từ file OpenAPI qua CLI.
- json-server: biến file JSON thành REST API nhanh để prototype.
Gợi ý chọn công cụ:
| Nhu cầu | Công cụ phù hợp |
|---|---|
| Test component React/Vue trong JS | MSW |
| Mock local nhanh bằng giao diện | Mockoon |
| Mock từ OpenAPI qua CLI | Prism |
| Mock server mạnh cho JVM/backend | WireMock |
| Prototype REST API từ JSON | json-server |
| Mock chia sẻ cho frontend, mobile, QA | Hosted mock API như Apidog |
Nếu vấn đề chính là “MSW không dùng được cho đồng đội không viết JavaScript”, hãy chọn một mock server dựa trên HTTP. Để xem thêm góc nhìn frontend, đọc bài về cách tạo mock API trong React với Axios.
Câu hỏi thường gặp
MSW có miễn phí không?
Có. Mock Service Worker là mã nguồn mở theo giấy phép MIT và miễn phí dùng trong cả dự án thương mại lẫn phi thương mại.
Bạn chỉ cần cân nhắc chi phí khi chuyển sang mock server được lưu trữ cho nhu cầu chia sẻ toàn đội. Các công cụ như Apidog cũng có gói miễn phí cho trường hợp này.
Apidog có thể thay thế MSW trong unit test không?
Không nên.
MSW chặn request bên trong JavaScript test runner như Jest hoặc Vitest. Apidog là nền tảng được lưu trữ, không phải thư viện import vào test file.
Cách dùng hợp lý:
- MSW: unit test, component test, local frontend test.
- Apidog: mock chia sẻ, mock từ schema, mock cho mobile/QA/backend/client không phải JS.
Nếu bạn chỉ tập trung vào test runner, xem thêm hướng dẫn về cách tạo mock lệnh gọi API.
MSW hoạt động trong Node hay chỉ trong trình duyệt?
Cả hai.
- Trong trình duyệt, MSW dùng Service Worker.
- Trong Node, MSW vá lớp request để handler chạy trong Jest, Vitest hoặc môi trường test Node.
Đây là một trong những lý do MSW rất phù hợp với đội JavaScript full-stack.
Khi nào nên bổ sung mock server được lưu trữ?
Hãy bổ sung mock server được lưu trữ khi có ít nhất một trong các dấu hiệu sau:
- mobile app hoặc backend test không dùng JavaScript cần gọi mock
- QA hoặc designer cần một URL ổn định
- nhiều đội cần cùng một mock endpoint
- API được thiết kế bằng OpenAPI trước khi backend hoàn thiện
- bạn muốn mock sinh tự động từ schema thay vì viết tay toàn bộ handler
Kết luận
MSW rất mạnh cho đúng phạm vi của nó: chặn request trong JavaScript để phục vụ frontend test, unit test và local development. Nó đơn giản, miễn phí, nằm trong repo và rất dễ tích hợp với Jest/Vitest.
Nhưng MSW không được thiết kế để trở thành mock server dùng chung, không phụ thuộc ngôn ngữ, có URL ổn định và sinh từ schema.
Cách tiếp cận thực tế là dùng cả hai:
- MSW cho test trong frontend repository.
- Apidog cho mock API được lưu trữ, chia sẻ, dựa trên schema và có thể gọi từ mọi HTTP client.
Nếu mock của bạn đã vượt ra khỏi phạm vi test runner, hãy trỏ frontend, mobile hoặc QA environment đến một mock server dùng chung để giảm phụ thuộc vào backend và giữ contract API nhất quán.



Top comments (0)