เริ่มต้นด้วยการทำความรู้จักโครงสร้างของการเขียน unit testing กันก่อนเลย

ใน jest และ test library ของภาษาอื่นๆ นั้นจะคล้ายๆ กัน โดยมีโครงสร้างแบบนี้

test('two plus two is four', () => {
  expect(2 + 2).toBe(4)
})

single test

หากว่ามีหลายๆ test แล้วต้องการจัดกลุ่มให้มัน เราจะใช้ describe

describe('Math function', () => {
  test('two plus two is four', () => {
    expect(2 + 2).toBe(4)
  })

  test('two multiply two is four', () => {
    expect(2 * 2).toBe(4)
  })
})

grouping test with describe


โครงสร้างการเขียน test

ในการเขียน test นั้น แนะนำให้ใช้สิ่งที่เรียกว่า 3A คือ

  • Arrange: การเตรียมการก่อนเริ่มทดสอบ
  • Action: การเรียกใช้งาน Function หรือ การทำอะไรสักอย่าง เพื่อให้ได้ผลการทดสอบ
  • Assert: การตรวจสอบความถูกต้อง

หน้าตามันเป็นแบบนี้

import { add } from "../src/math"

it('message', () => {
  // Arrange
  const num1 = 5
  const num2 = 3
  const actual = 8

  // Action
  const result = add(num1, num2)
  
  // Assert
  expect(result).toEqual(actual)
})

3A


การทดสอบแบบ Asynchronous

เป็นเรื่องปกติใน JavaScript โค้ดที่เราเขียน จะมีการทำงานแบบ asynchronous และเมื่อโค้ดของเรามีการทำงานแบบ asynchronous ตัว jest จำเป็นต้องรู้ว่าโค้ดที่กำลังทดสอบเสร็จสมบูรณ์เมื่อไหร่ ก่อนที่จะสามารถไปยังการทดสอบอื่นได้

โดย Jest มีหลายวิธีในการจัดการเรื่องนี้

Promises

​การ return ค่า แบบ promise ภายใน code ของเรา jest จะรอให้ promise นั้น resolve ก่อน แต่ถ้าหากมีการ rejected จาก promise เท่ากับว่าการทดสอบนั้นล้มเหลว

test('the data is peanut butter', () => {
  return fetchData().then((data) => {
    expect(data).toBe('peanut butter')
  })
})

promise resolve

หากเราต้องการทดสอบ reject ของ promise ให้ใช้วิธี .catch

test('the fetch fails with an error', () => {
  expect.assertions(1)
  return fetchData().catch((error) => {
    expect(error).toMatch('error messages')
  })
})

promise reject

expect.assertions ใส่เข้ามาเพื่อตรวจสอบว่า มีการเรียกการเรียกใช้งานจริงๆ หากเราไม่ได้ใส่มันเข้าไปด้วย การทดสอบมันจะไม่ fail


Async/Await

เราสามารถใช้ async และ await ในการทดสอบของเราได้ หากต้องการเขียนการทดสอบแบบ async ให้ใช้คีย์เวิร์ด async หน้าฟังก์ชันที่ผ่านการทดสอบ

ตัวอย่าง เช่น สถานการณ์จำลอง fetchData เดียวกัน สามารถทดสอบได้ด้วย:

test('the data is peanut butter', async () => {
  const data = await fetchData()
  expect(data).toBe('peanut butter')
})

test('the fetch fails with an error', async () => {
  expect.assertions(1)
  try {
    await fetchData()
  } catch (error) {
    expect(error).toMatch('error')
  }
})

async/await with try catch

expect.assertions(1) ใช้เพื่อตรวจาสอบว่า assertions ถูกเรียกหรือเปล่า

หรือ เราสามารถรวม async และ await กับ .resolves หรือ .rejects ก็ได้

test('the data is peanut butter', async () => {
  await expect(fetchData()).resolves.toBe('peanut butter')
})

test('the fetch fails with an error', async () => {
  await expect(fetchData()).rejects.toMatch('error')
})

async/await with resolve & reject


Callbacks

ถ้าหากเราต้องการทดสอบ function ที่มีการใช้ callback นั้น ก็สามารถ ใช้งานได้ ดังนี้

test('the data is peanut butter', (done) => {
  function callback(error: string | null, data: string | null) {
    if (error) {
      done(error)
      return
    }
    try {
      expect(data).toBe('peanut butter')
      done()
    } catch (error) {
      done(error)
    }
  }

  fetchDataWithCallback(callback)
})

testing with callback function