หากคุณเขียนการทดสอบฝั่งฟรอนต์เอนด์ คุณอาจเคยใช้ Mock Service Worker (MSW) เพื่อดักจับคำขอในเบราว์เซอร์และ Node บทความนี้สรุปแบบลงมือทำว่า MSW เหมาะกับงานแบบใด, ควรตั้งค่าอย่างไร, จุดที่เริ่มไม่พอสำหรับทีมขนาดใหญ่, และเมื่อใดที่ควรเพิ่ม แพลตฟอร์มจำลอง API แบบโฮสต์เข้ามาใช้ร่วมกัน
Mock Service Worker คืออะไร?
Mock Service Worker เป็นไลบรารี JavaScript สำหรับดักจับคำขอเครือข่ายที่ต้นทาง
- ในเบราว์เซอร์: ใช้ Service Worker เพื่อดัก
fetchและXMLHttpRequest - ใน Node: ดักเลเยอร์คำขอเพื่อให้ใช้กับ Jest, Vitest หรือ test runner อื่นได้
- คุณเขียน handler ตาม method และ path แล้วส่ง response ที่ต้องการกลับไป
ข้อดีคือโค้ดแอปของคุณยังเรียก API ตามปกติ ไม่ต้อง stub fetch และไม่ต้องเปลี่ยน HTTP client เช่น Axios หรือ native fetch ดูรายละเอียด implementation ได้จาก ซอร์สโค้ดของ MSW บน GitHub
ตัวอย่าง handler พื้นฐาน:
import { http, HttpResponse } from 'msw'
export const handlers = [
http.get('/api/users/:id', ({ params }) => {
return HttpResponse.json({
id: params.id,
name: 'Ada Lovelace',
})
}),
]
จากนั้นนำ handler ไปใช้ทั้งใน test และ dev environment ได้
วิธีใช้ MSW ในโปรเจกต์ฟรอนต์เอนด์
โครงสร้างที่ใช้บ่อย:
src/
mocks/
handlers.js
browser.js
server.js
components/
tests/
1. สร้าง handler
// src/mocks/handlers.js
import { http, HttpResponse } from 'msw'
export const handlers = [
http.get('/api/users/:id', ({ params }) => {
return HttpResponse.json({
id: params.id,
name: 'Ada Lovelace',
email: 'ada@example.com',
})
}),
http.get('/api/users', () => {
return HttpResponse.json([
{ id: '1', name: 'Ada Lovelace' },
{ id: '2', name: 'Grace Hopper' },
])
}),
]
2. ใช้ในเบราว์เซอร์ระหว่าง local development
// src/mocks/browser.js
import { setupWorker } from 'msw/browser'
import { handlers } from './handlers'
export const worker = setupWorker(...handlers)
เรียกใช้งานเฉพาะตอน development:
// src/main.js หรือ src/main.ts
async function enableMocking() {
if (import.meta.env.MODE !== 'development') {
return
}
const { worker } = await import('./mocks/browser')
return worker.start()
}
enableMocking().then(() => {
// render app
})
3. ใช้ใน Node test runner
// src/mocks/server.js
import { setupServer } from 'msw/node'
import { handlers } from './handlers'
export const server = setupServer(...handlers)
ตัวอย่าง setup สำหรับ Vitest หรือ Jest:
// src/setupTests.js
import { beforeAll, afterEach, afterAll } from 'vitest'
import { server } from './mocks/server'
beforeAll(() => server.listen())
afterEach(() => server.resetHandlers())
afterAll(() => server.close())
MSW โดดเด่นในงานแบบใด
MSW เหมาะมากเมื่อ mock และ consumer อยู่ใน codebase เดียวกัน โดยเฉพาะงานเหล่านี้:
1. Unit test และ component test
คุณสามารถ render component ให้ยิง request จริง แล้วให้ MSW ส่ง response ที่ควบคุมได้กลับมา
import { render, screen } from '@testing-library/react'
import UserProfile from './UserProfile'
test('renders user profile', async () => {
render(<UserProfile userId="1" />)
expect(await screen.findByText('Ada Lovelace')).toBeInTheDocument()
})
วิธีนี้ต่างจากการ mock HTTP client โดยตรง เช่น jest.fn() หรือ spy บน Axios หากต้องการเปรียบเทียบแนวทาง ดูบทความเรื่อง Jest mock ของการเรียก API
2. Local frontend development
ถ้า backend ยังไม่พร้อม คุณสามารถสร้าง UI ต่อได้ทันที:
http.get('/api/orders', () => {
return HttpResponse.json([
{ id: 'ord_1', status: 'paid', total: 1200 },
{ id: 'ord_2', status: 'pending', total: 800 },
])
})
ต้องการทดสอบ loading, empty state หรือ error ก็เปลี่ยน handler ได้:
http.get('/api/orders', () => {
return new HttpResponse(null, { status: 500 })
})
3. CI ที่คาดการณ์ผลลัพธ์ได้
เมื่อ test ไม่เรียก staging server จริง ปัญหาเรื่อง network, shared data หรือ rate limit จะลดลง ทำให้ pipeline เสถียรกว่า
4. ทีม JavaScript ทีมเดียว
ถ้าคนเขียน mock คือคนเดียวกับที่ใช้ mock การเก็บ handler ใน repo เดียวกับ test เป็นวิธีที่ง่ายและ maintain ได้ดี
ถ้า use case ของคุณอยู่ในกลุ่มนี้ MSW อาจเพียงพอแล้ว เพราะฟรี, เป็นโอเพนซอร์ส และออกแบบมาเพื่อ JavaScript testing โดยตรง
เมื่อ MSW เริ่มไม่พอ
ข้อจำกัดหลักของ MSW มาจากจุดแข็งของมันเอง: mock อยู่ในโค้ด JavaScript และรันใน process ของแอปหรือ test runner
ผู้ใช้งานที่ไม่ใช่ JavaScript
handler ของ MSW เป็น JavaScript ดังนั้นทีม mobile ที่ใช้ Swift/Kotlin หรือ backend integration test ที่ใช้ Go/Python จะนำ handler เหล่านี้ไปใช้ตรง ๆ ไม่ได้
ถ้าหลาย client ต้องใช้ mock ชุดเดียวกัน ทางเลือกที่เหมาะกว่าคือ เซิร์ฟเวอร์จำลอง ที่ expose ผ่าน HTTP URL จริง
ตัวอย่างสถานการณ์:
Frontend React -> ต้องการ mock
iOS Swift -> ต้องการ mock เดียวกัน
Android Kotlin -> ต้องการ mock เดียวกัน
QA automation -> ต้องการ mock เดียวกัน
MSW แก้เฉพาะฝั่ง JavaScript ได้ดี แต่ไม่ใช่ mock กลางของทุกทีม
ต้องการ URL กลางที่เปิดตลอดเวลา
MSW ทำงานใน browser tab หรือ test process ไม่มี URL กลางให้ QA, designer หรือ partner team เรียกจากเครื่องตัวเอง
ถ้าคุณต้องการ endpoint เช่น:
https://mock.company.dev/api/users/1
คุณต้องใช้ hosted mock server ไม่ใช่ Service Worker ที่ผูกกับเครื่อง developer คนใดคนหนึ่ง
เวิร์กโฟลว์แบบ spec-first
ถ้าทีมออกแบบ API ด้วย OpenAPI ก่อนเขียนโค้ด คุณมักต้องการ mock ที่สร้างจาก schema โดยตรง เพื่อให้ response ไม่หลุดจาก contract
MSW ต้องเขียน handler เอง เช่น:
http.post('/api/payments', async ({ request }) => {
const body = await request.json()
return HttpResponse.json({
id: 'pay_123',
amount: body.amount,
status: 'created',
})
})
แต่ใน workflow แบบ schema-first คุณอาจต้องการให้ mock ถูกสร้างจาก OpenAPI อัตโนมัติ อ่านเพิ่มเติมได้ในคู่มือเรื่อง การจำลอง API
ต้องการข้อมูล mock ที่สมจริงจำนวนมาก
MSW จะส่งข้อมูลตามที่คุณเขียนเอง หาก API มีหลาย field คุณต้องสร้างข้อมูลเองหรือใช้ library เสริม เช่น faker
import { faker } from '@faker-js/faker'
http.get('/api/users', () => {
return HttpResponse.json(
Array.from({ length: 20 }).map(() => ({
id: faker.string.uuid(),
name: faker.person.fullName(),
email: faker.internet.email(),
createdAt: faker.date.past().toISOString(),
}))
)
})
วิธีนี้ยืดหยุ่น แต่เมื่อ endpoint เยอะขึ้น ค่า maintain handler และ fake data จะเพิ่มขึ้นตาม
MSW เทียบกับแพลตฟอร์มจำลอง API เต็มรูปแบบ
ไม่มีตัวเลือกใดดีกว่าเสมอไป ทั้งสองแบบแก้ปัญหาคนละระดับ
| ความสามารถ | Mock Service Worker | แพลตฟอร์ม API แบบโฮสต์ เช่น Apidog |
|---|---|---|
| รันใน JS unit/component tests | ใช่, เป็น native | ไม่ใช่ JavaScript test library |
| ใช้ได้ข้ามภาษาผ่าน HTTP | ไม่, เน้น JavaScript | ใช่, client ใดก็เรียกได้ |
| มี URL กลางให้ทั้งทีม | ไม่ | ใช่, เป็น hosted mock server |
| สร้าง mock จาก OpenAPI | ต้องเขียนเอง | สร้างจาก schema ได้ |
| ข้อมูล dynamic / realistic | ต้องเขียน logic เอง | มีเครื่องมือช่วยสร้างข้อมูล |
| อยู่ใน repo เดียวกับ test | ใช่ | อยู่ใน project ที่แชร์ร่วมกัน |
| ค่าใช้จ่าย | ฟรี, โอเพนซอร์ส | มี free tier และ paid plan |
สรุปแบบใช้งานจริง:
- ใช้ MSW สำหรับ frontend unit/component tests
- ใช้ hosted API mocking เมื่อ mock ต้องแชร์ข้ามทีม, ข้ามภาษา หรือสร้างจาก spec
แพลตฟอร์มอย่าง Apidog เหมาะกับกรณีหลังมากกว่า
Apidog เป็นส่วนเสริม ไม่ใช่สิ่งทดแทน MSW
Apidog ไม่ได้แทนที่ MSW ใน Jest หรือ Vitest เพราะ Apidog ไม่ใช่ JavaScript library ที่ import เข้า test file ได้
ให้มองแบบนี้:
MSW = mock ภายใน repo/test runner ของ JavaScript
Apidog = mock server กลางที่แชร์ผ่าน HTTP URL
workflow ที่ใช้ร่วมกันได้:
- ออกแบบหรือนำเข้า API schema ใน Apidog
- สร้าง mock endpoint จาก schema
- แชร์ mock URL ให้ frontend, mobile และ QA
- ใช้ MSW ต่อไปสำหรับ unit/component tests ภายใน frontend repo
ตัวอย่างการแบ่งงาน:
React component test -> ใช้ MSW
Local UI development -> ใช้ MSW หรือ hosted mock
Mobile app development -> ใช้ hosted mock URL
QA automation -> ใช้ hosted mock URL
API design review -> ใช้ schema + hosted mock
เมื่อ mock ถูกผูกกับ schema เดียวกับ design และ test จะช่วยลดโอกาสที่ response mock จะหลุดจาก API contract หากต้องการดูเครื่องมือหลายตัวเปรียบเทียบกัน อ่านคู่มือ เครื่องมือจำลอง API ที่ดีที่สุด
แนวทางที่หลายทีมใช้ได้ดี:
- MSW สำหรับ test ภายใน frontend repo
- Hosted mock สำหรับ integration, demo, mobile, QA และผู้ใช้งานที่ไม่ใช่ JavaScript
คุณไม่จำเป็นต้องเลือกอย่างใดอย่างหนึ่ง ใช้แต่ละเครื่องมือในจุดที่เหมาะสม หากต้องการลองฝั่ง hosted mock ควบคู่กับ MSW ที่มีอยู่ สามารถ ดาวน์โหลด Apidog
ทางเลือกอื่นของ MSW ที่ควรรู้
MSW ไม่ใช่ตัวเลือกเดียว ขึ้นอยู่กับ stack และ workflow ของทีม:
- Mockoon: แอปเดสก์ท็อปสำหรับสร้าง local mock server ด้วย GUI
- WireMock: mock server ที่ใช้ Java เหมาะกับทีม JVM และ contract testing
- Prism โดย Stoplight: สร้าง mock จาก OpenAPI ผ่าน command line
- json-server: เปลี่ยนไฟล์ JSON เป็น REST API สำหรับ prototype อย่างรวดเร็ว
ตัวอย่างการใช้ json-server:
npx json-server db.json --port 3001
{
"users": [
{ "id": 1, "name": "Ada Lovelace" },
{ "id": 2, "name": "Grace Hopper" }
]
}
จากนั้นเรียกได้ที่:
http://localhost:3001/users
ถ้าปัญหาของคุณคือ “MSW ใช้กับเพื่อนร่วมทีมที่ไม่ใช่ JavaScript ไม่ได้” mock server ที่ expose ผ่าน HTTP ก็ช่วยได้ สำหรับมุมมองฝั่ง React เพิ่มเติม ดูบทความเรื่อง การจำลอง API ใน React ด้วย Axios
Checklist: ควรใช้ MSW หรือ hosted mock?
ใช้ MSW ถ้า:
- mock ใช้เฉพาะใน frontend repo
- test รันใน Jest, Vitest หรือ browser environment
- ทีมหลักเป็น JavaScript/TypeScript
- ต้องการ mock ที่ version control ไปพร้อม test
- ต้องการควบคุม response แบบละเอียดด้วยโค้ด
ใช้ hosted mock ถ้า:
- mobile, backend, QA หรือ partner ต้องใช้ mock เดียวกัน
- ต้องการ URL กลางที่เรียกได้ตลอดเวลา
- ทำงานแบบ OpenAPI/spec-first
- ต้องการ mock data ที่สร้างจาก schema
- ต้องการ demo API ก่อน backend พร้อม
ใช้ทั้งคู่ถ้า:
Unit/component tests -> MSW
Cross-team API mock -> hosted mock
คำถามที่พบบ่อย
MSW ฟรีหรือไม่?
ฟรี Mock Service Worker เป็นโอเพนซอร์สภายใต้ใบอนุญาต MIT และใช้งานได้ทั้งโปรเจกต์ส่วนตัวและเชิงพาณิชย์ ค่าใช้จ่ายจะเริ่มเกี่ยวข้องเมื่อคุณต้องการแพลตฟอร์มแบบโฮสต์สำหรับ mock ที่แชร์ร่วมกัน ซึ่งเครื่องมืออย่าง Apidog ก็มีบริการฟรีให้เริ่มใช้งานได้
Apidog สามารถแทนที่ MSW ใน unit test ได้หรือไม่?
ไม่ควรใช้แทนกันโดยตรง MSW ดักจับ request ภายใน JavaScript test runner ส่วน Apidog เป็นแพลตฟอร์มแบบโฮสต์ ไม่ใช่ library ที่ import เข้า Jest หรือ Vitest ได้
ใช้ Apidog สำหรับ mock ที่ต้องแชร์ข้ามทีม, ข้ามภาษา หรือขับเคลื่อนด้วย schema หากโฟกัสอยู่ที่ test runner อย่างเดียว บทความ วิธีการจำลองการเรียก API จะเหมาะกว่า
MSW ทำงานใน Node หรือเฉพาะเบราว์เซอร์?
ทำงานได้ทั้งสองแบบ
- Browser: ใช้ Service Worker
- Node: ดัก request layer เพื่อใช้ใน Jest, Vitest หรือ Node test environment
นี่คือเหตุผลที่ MSW เหมาะกับทีม JavaScript ที่ต้องการใช้ handler ชุดเดียวกันทั้งใน dev และ test
ควรเปลี่ยนจาก MSW ไปใช้ hosted mock เมื่อใด?
ไม่จำเป็นต้อง “เปลี่ยน” เสมอไป หลายทีมใช้แบบ “เพิ่ม” hosted mock เข้ามาเมื่อมีสัญญาณเหล่านี้:
- client ที่ไม่ใช่ JavaScript ต้องใช้ mock
- หลายทีมต้องการ URL เดียวกัน
- API ถูกออกแบบแบบ spec-first
- ต้องการ mock ที่สร้างจาก OpenAPI
- ต้องการ mock server สำหรับ demo หรือ QA automation
สรุป
MSW เหมาะมากสำหรับการดักจับ request ใน JavaScript โดยเฉพาะ unit test, component test และ local frontend development แต่ไม่ได้ออกแบบมาเป็น mock server กลางที่แชร์ข้ามภาษาและข้ามทีม
เมื่อ mock ต้องออกจาก repo, ต้องมี URL จริง, ต้องใช้ร่วมกับ mobile/QA/backend หรืออยากสร้างจาก OpenAPI schema ให้เพิ่มแพลตฟอร์ม mock แบบโฮสต์เข้ามา
Apidog ช่วยในส่วนที่ MSW ไม่ได้โฟกัส: hosted mock server, mock URL ที่แชร์ได้, การสร้าง mock จาก API design และข้อมูล response ที่สมจริงตั้งแต่เริ่มต้น ให้ MSW ทำงานใน test runner ต่อไป และให้ Apidog ดูแล mock ที่ต้องใช้ร่วมกันนอก repo หากต้องการลองใช้งาน สามารถ ดาวน์โหลด Apidog แล้วชี้ frontend ของคุณไปยัง mock URL กลางเพื่อทดสอบ workflow ได้ทันที



Top comments (0)