สวัสดีครับกลับมาพบกับบทความป้ายยาเครื่องมือดี ๆ ใช้ฟรี ๆ กันอีกครั้ง! วันนี้ผมจะพาทุกคนไปรู้จักกับ Vitest เครื่องมือที่จะใช้ในการทดสอบโค้ดที่ใช้ง่าย และไวกัน 💨
Vitest คืออะไร?
Vitest เป็นเฟรมเวิร์กสำหรับทดสอบโค้ด JavaScript ที่ถูกพัฒนาโดย Vite ทีมพัฒนาเดียวกันกับ Vite.js ที่โด่งดังเรื่องความเร็วแรง เดี๋ยวนี้ตอนผมสร้างโปรเจกต์ React ก็ใช้เจ้า Vite นี่แหละ โดย Vitest จะรองรับการทดสอบทั้ง Unit Tests, Integration Tests และ End-to-End Tests แถม เร็วกว่า Jest ถึง 2-3 เท่า! เหมาะกับการทดสอบโค้ดจำนวนมาก
มือใหม่อยากลองเล่น เค้าก็มีเป็น Vitest Online ให้เราลองไปใช้ได้นะ https://stackblitz.com/edit/vitest-dev-vitest-2l5ntf?file=src%2Fbasic.ts,test%2Fbasic.test.ts&initialPath=__vitest__/
เริ่มต้นใช้งาน Vitest ในโปรเจกต์
1. ติดตั้ง Vitest
npm install -D vitest
โดยหมายเหตุไว้นิดนึงว่า Vitest 1.0 ต้องใช้ Vite >=v5.0.0 และ Node >=v18.00
2. เขียน Unit Test ด้วย Vitest
โดยเราจะมาเริ่มกันที่ฟังก์ชันง่าย ๆ อย่างฟังก์ชันที่ใช้ในการบวกเลขกัน โดยการสร้างไฟล์ชื่อว่า sum.js โดยไฟล์นี้
// sum.js
export function sum(a, b) {
return a + b
}
เมื่อเราได้ไฟล์หรือฟังก์ชันที่ต้องการทดสอบแล้วเราก็มาเขียนไฟล์ Test กันเลย โดยไฟล์ Test โดยไฟล์เทสจะต้องมีคำว่า “.test.” หรือ “.spec.” อยู่ในชื่อไฟล์ด้วย
// sum.test.js
import { expect, test } from 'vitest'
import { sum } from './sum'
test('adds 1 + 2 to equal 3', () => {
expect(sum(1, 2)).toBe(3)
})
สิ่งที่อยู่ในโค้ดตัวอย่าง (sum.test.js)
import { expect, test } from 'vitest'
: เรียกใช้งานโมดูลexpect
และtest
จาก Vitestimport { sum } from './sum'
: โหลดฟังก์ชันsum
จากไฟล์sum.js
(ที่อยู่ในโฟลเดอร์เดียวกัน) เพื่อเอามารันเทสtest('adds 1 + 2 to equal 3', () => { ... })
:test
: ฟังก์ชันสำหรับสร้าง test case หรือกรณีที่เราทดสอบ'adds 1 + 2 to equal 3'
: ข้อความที่ใช้อธิบายว่า test case นี้ทำอะไร
expect(sum(1, 2)).toBe(3)
:expect
ใน Vitest คำสั่ง expect เป็นฟังก์ชันสำหรับสร้าง assertions เพื่อเอาไว้ดูว่าผลลัพธที่ได้จากโปรแกรมตรงกับค่าที่เราหวังมั้ยexpect(sum(1, 2))
: เป็นการเรียกฟังก์ชันsum
กับตัวเลข 1 และ 2 ใส่ไปใน expect เพื่อเอาค่าที่ได้นี้ไปเช็คกับ matcher ด้านล่าง.toBe(3)
: อันนี้เราเรียกว่า matcher ที่ชื่อ.toBe
โดยมันจะทำการตรวจสอบว่าค่าใน Expect เท่ากันเป๊ะ ๆ กับ 3 มั้ย
โดย matcher ไม่ได้มีแค่ toBe เท่านั้น โดยใน Vitest มี matcher อื่น ๆ อีกมากมาย สามารถอ่านเพิ่มเติมเกี่ยวกับการใช้ matcher ได้ที่ลิงก์นี้ https://vitest.dev/api/expect-typeof.html#asserts
3. รันยังไง?
เมื่อเรามีฟังก์ชัน และเขียน Unit Test ให้กับฟังก์ชันเรียบร้อยแล้ว เราก็ต้องมาลองรันใช่มั้ยครับ โดยก่อนอื่นให้เราไปที่ไฟล์ package.json แล้วเปลี่ยนคำสั่ง test ใน scripts ให้เป็น vitest ดังนี้
package.json
{
"scripts": {
"test": "vitest"
}
}
ตอนที่เรารันเราสามารกใช้คำสั่ง npm test ได้เลย แล้วเจ้าตัว vitest ก็จะแสดงข้อความตามนี้มา
- DEV v1.4.0 C:/Users/User/Content/Vitest_Example
DEV
: หมายถึงโปรเจกต์นี้กำลังอยู่ในโหมด development (การพัฒนา)v.1.4.0
: เวอร์ชั่นของ Vitest ที่ใช้C:/Users/User/Content/Vitest_Example
: ตำแหน่งของโปรเจกต์
- ✓ sum.test.js (1)
✓
: สัญลักษณ์บอกว่า test case ในไฟล์sum.test.js
ผ่าน(1)
: ระบุว่ามี test case จำนวน 1 ในไฟล์นี้
- ✓ adds 1 + 2 to equal 3
- ข้อความอธิบาย test case ที่ผ่าน
- Test Files 1 passed (1): มี 1 test file ผ่าน
- Tests 1 passed (1): มี 1 test case ผ่าน
- Start at 10:28:05: เวลาเริ่มต้นรัน test
- Duration 270ms …: ระยะเวลาในการรัน test ทั้งหมด กับเวลาย่อยของแต่ละขั้นตอน
- PASS Waiting for file changes…: การทดสอบเสร็จสมบูรณ์ Vitest กำลังรอตรวจจับการเปลี่ยนแปลงไฟล์อยู่เพื่อทดสอบใหม่อีกครั้ง
press h to show help
: กด ‘h’ เพื่อดูเมนูช่วยเหลือpress q to quit
: กด ‘q’ เพื่อออกจาก Vitest
4. การเปิดใช้งาน Test Coverage
เราสามารถดูว่าการเขียน Unit Test ของเรามันคลุมทุกฟังก์ชันเลยหรือป่าว ขาดตกส่วนไหนไปบ้างสามารถใช้ coverage ดูตรงนี้ได้
อย่างเช่นไฟล์ math.js
function add(x, y) {
return x + y;
}
function subtract(x, y) {
return x - y;
}
function multiply(x, y) {
return x * y;
}
function divide(x, y) {
if (y === 0) {
throw new Error("Cannot divide by zero!");
}
return x / y;
}
module.exports = { add, subtract, multiply, divide };
แล้วทำการเขียน Unit Test โดยขาดการเทสฟังก์ชัน divide ไป
import { describe, it, expect } from "vitest";
import { add, subtract, multiply, divide } from "./math"; // Adjust the path if necessary
describe("math functions", () => {
it("add", () => {
expect(add(2, 3)).toBe(5);
expect(add(0, 5)).toBe(5);
expect(add(-3, 5)).toBe(2);
});
it("subtract", () => {
expect(subtract(5, 3)).toBe(2);
expect(subtract(0, 5)).toBe(-5);
expect(subtract(-3, 5)).toBe(-8);
});
it("multiply", () => {
expect(multiply(2, 3)).toBe(6);
expect(multiply(0, 5)).toBe(0);
expect(multiply(-3, 5)).toBe(-15);
});
});
หากใช้ npm test เราจะเห็นแต่เทสผ่านกี่ไฟล์ กี่ฟังก์ชัน แต่ไม่เห็นว่าเทสครบมั้ย
หากเราจะเปิดใช้งาน coverage ให้ไปที่ไฟล์ package.json แล้วเพิ่ม “coverage”: “vitest run –coverage” ขึ้นมา
"scripts": {
"test": "vitest",
"coverage": "vitest run --coverage"
},
หลังจากนั้นลองรันโดยใช้คำสั่ง
npm run coverage
จะเห็นได้ว่ามี coverage report เพิ่มมาให้
- ไฟล์
sum.js
ถูกทดสอบครบถ้วน 100% - ไฟล์
math.js
มีบางส่วนที่ยังไม่ได้ทดสอบ: บรรทัด 13-18
- % Stmts: เปอร์เซ็นต์ของคำสั่งในไฟล์ที่ถูกทดสอบ
- % Branch: เปอร์เซ็นต์ของเงื่อนไขในไฟล์ที่ถูกทดสอบ
- % Funcs: เปอร์เซ็นต์ของฟังก์ชันในไฟล์ที่ถูกทดสอบ
- % Lines: เปอร์เซ็นต์ของบรรทัดในไฟล์ที่ถูกทดสอบ
- Uncovered Line #s: หมายเลขบรรทัดที่ไม่ได้ทดสอบ
Vitest UI
ซึ่งนอกจากนั้น Vitest ยังมี Report ที่เป็น UI สวย ๆ มาให้ใช้ได้ด้วย เพียงเราทำการติดตั้งโดยใช้คำสั่ง
npm i -D @vitest/ui
และทำการรันโดยการใช้คำสั่ง
npx vitest --ui
โดยเราสามารถดู Vitest UI ได้เลยที่ http://localhost:51204/__vitest__/
และนี่ก็จะวิธีการใช้งาน Vitest ในการทำ Unit Test สำหรับโค้ด JavaScript แบบง่าย ๆ ถ้าใครอยากไปลองเล่นต่อสามารถลองใช้งานตาม Document นี้ได้เลยยย https://vitest.dev/guide/why.html