DEV Community

Cover image for ทางเลือก Mock Service Worker (MSW): เมื่อไหร่ที่ควรใช้แพลตฟอร์ม Mock API แบบครบวงจร
Thanawat Wongchai
Thanawat Wongchai

Posted on • Originally published at apidog.com

ทางเลือก Mock Service Worker (MSW): เมื่อไหร่ที่ควรใช้แพลตฟอร์ม Mock API แบบครบวงจร

หากคุณเขียนการทดสอบฝั่งฟรอนต์เอนด์ คุณอาจเคยใช้ Mock Service Worker (MSW) เพื่อดักจับคำขอในเบราว์เซอร์และ Node บทความนี้สรุปแบบลงมือทำว่า MSW เหมาะกับงานแบบใด, ควรตั้งค่าอย่างไร, จุดที่เริ่มไม่พอสำหรับทีมขนาดใหญ่, และเมื่อใดที่ควรเพิ่ม แพลตฟอร์มจำลอง API แบบโฮสต์เข้ามาใช้ร่วมกัน

ลองใช้ Apidog วันนี้

Mock Service Worker คืออะไร?

Mock Service Worker เป็นไลบรารี JavaScript สำหรับดักจับคำขอเครือข่ายที่ต้นทาง

  • ในเบราว์เซอร์: ใช้ Service Worker เพื่อดัก fetch และ XMLHttpRequest
  • ใน Node: ดักเลเยอร์คำขอเพื่อให้ใช้กับ Jest, Vitest หรือ test runner อื่นได้
  • คุณเขียน handler ตาม method และ path แล้วส่ง response ที่ต้องการกลับไป

Mock Service Worker

ข้อดีคือโค้ดแอปของคุณยังเรียก 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',
    })
  }),
]
Enter fullscreen mode Exit fullscreen mode

จากนั้นนำ handler ไปใช้ทั้งใน test และ dev environment ได้

วิธีใช้ MSW ในโปรเจกต์ฟรอนต์เอนด์

โครงสร้างที่ใช้บ่อย:

src/
  mocks/
    handlers.js
    browser.js
    server.js
  components/
  tests/
Enter fullscreen mode Exit fullscreen mode

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' },
    ])
  }),
]
Enter fullscreen mode Exit fullscreen mode

2. ใช้ในเบราว์เซอร์ระหว่าง local development

// src/mocks/browser.js
import { setupWorker } from 'msw/browser'
import { handlers } from './handlers'

export const worker = setupWorker(...handlers)
Enter fullscreen mode Exit fullscreen mode

เรียกใช้งานเฉพาะตอน 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
})
Enter fullscreen mode Exit fullscreen mode

3. ใช้ใน Node test runner

// src/mocks/server.js
import { setupServer } from 'msw/node'
import { handlers } from './handlers'

export const server = setupServer(...handlers)
Enter fullscreen mode Exit fullscreen mode

ตัวอย่าง 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())
Enter fullscreen mode Exit fullscreen mode

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()
})
Enter fullscreen mode Exit fullscreen mode

วิธีนี้ต่างจากการ 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 },
  ])
})
Enter fullscreen mode Exit fullscreen mode

ต้องการทดสอบ loading, empty state หรือ error ก็เปลี่ยน handler ได้:

http.get('/api/orders', () => {
  return new HttpResponse(null, { status: 500 })
})
Enter fullscreen mode Exit fullscreen mode

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 เดียวกัน
Enter fullscreen mode Exit fullscreen mode

MSW แก้เฉพาะฝั่ง JavaScript ได้ดี แต่ไม่ใช่ mock กลางของทุกทีม

ต้องการ URL กลางที่เปิดตลอดเวลา

MSW ทำงานใน browser tab หรือ test process ไม่มี URL กลางให้ QA, designer หรือ partner team เรียกจากเครื่องตัวเอง

ถ้าคุณต้องการ endpoint เช่น:

https://mock.company.dev/api/users/1
Enter fullscreen mode Exit fullscreen mode

คุณต้องใช้ 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',
  })
})
Enter fullscreen mode Exit fullscreen mode

แต่ใน 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(),
    }))
  )
})
Enter fullscreen mode Exit fullscreen mode

วิธีนี้ยืดหยุ่น แต่เมื่อ 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
Enter fullscreen mode Exit fullscreen mode

workflow ที่ใช้ร่วมกันได้:

  1. ออกแบบหรือนำเข้า API schema ใน Apidog
  2. สร้าง mock endpoint จาก schema
  3. แชร์ mock URL ให้ frontend, mobile และ QA
  4. ใช้ MSW ต่อไปสำหรับ unit/component tests ภายใน frontend repo

Apidog API mocking

ตัวอย่างการแบ่งงาน:

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
Enter fullscreen mode Exit fullscreen mode

เมื่อ mock ถูกผูกกับ schema เดียวกับ design และ test จะช่วยลดโอกาสที่ response mock จะหลุดจาก API contract หากต้องการดูเครื่องมือหลายตัวเปรียบเทียบกัน อ่านคู่มือ เครื่องมือจำลอง API ที่ดีที่สุด

API mock tools

แนวทางที่หลายทีมใช้ได้ดี:

  • 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
Enter fullscreen mode Exit fullscreen mode
{
  "users": [
    { "id": 1, "name": "Ada Lovelace" },
    { "id": 2, "name": "Grace Hopper" }
  ]
}
Enter fullscreen mode Exit fullscreen mode

จากนั้นเรียกได้ที่:

http://localhost:3001/users
Enter fullscreen mode Exit fullscreen mode

ถ้าปัญหาของคุณคือ “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
Enter fullscreen mode Exit fullscreen mode

คำถามที่พบบ่อย

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)