จากบทความที่แล้ว ที่เป็นเรื่องของ mock function ใน jest

การใช้งาน Mock ใน Jest
เริ่มต้นที่ ทำความเข้าใจเกี่ยวกับ Test Double กันก่อน สรุปเกี่ยวกับ Test Doubleมัน คือ เทคนิคการเขียนโปรแกรมที่ใช้สร้าง ”ตัวแทน” ของ object จริง เพื่อใช้งานในการเขียน unit test ให้นึกภาพเป็น ”สตั้นแมน” ในภาพยนตร์ก็ได้ ที่เข้

หากเราต้องการที่จะจำลองการใช้งานของฟังก์ชั่นภายในไฟล์เดียวกัน เราจะต้องใช้งาน spy แทนการใช้งาน mock

โดยบทความนี้เราจะมาพูดถึงการใช้งาน spy ใน jest กัน

Spy

อธิบายเกี่ยวกับ spy แบบง่ายๆ เลย มันก็เป็นเหมือนการสอดส่อง ฟังก์ชั่นที่เราต้องการจะจับตามันและตรวจสอบว่า...

  • ฟังก์ชั่นถูกเรียกหรือไม่
  • ฟังก์ชั่นถูกเรียกกี่ครั้ง
  • ตรวจสอบ arguments ที่ส่งไปยังฟังก์ชั่น
  • ตรวจสอบค่าที่ return จากฟังก์ชั่น

รวมถึง mocking return ฟังก์ชั่นภายในไฟล์เดียวกันกับไฟล์ที่ต้องการทดสอบ

เราลองมาดูตัวอย่างกันเลย

Spy Self File

export const doubleSum = (x: number, y: number): number => {
  const sum = add(x, y)
  return x + y + sum
}

export const add = (x: number, y: number): number => {
  return x + y
}

calculate.ts

หากเราต้องการทดสอบฟังก์ชั่น add() ได้มีการถูกเรียกใช้งานหรือไม่ เราจะเขียนการทดสอบได้ดังนี้

import * as calculate from './calculate'

describe('spy self', () => {
  it('Should be called add when call doubleSum', () => {
    const x = 2
    const y = 2

    const mathAddSpy = jest.spyOn(calculate, 'add')

    calculate.doubleSum(x, y)

    expect(mathAddSpy).toHaveBeenCalled()
  })
})

calculate.test.ts

หากต้องการที่จะทดสอบว่าฟังก์ชั่น add() มีการเรียกใช้งานกี่ครั้ง ให้ใช้ .toHaveBeenCalledTimes(1)

อย่าลืม เพิ่ม jest.restoreAllMocks() เข้าไปด้วย เพื่อให้มันเคลียค่าทุกครั้งในแต่ละการทดสอบ ถ้าไม่ได้ใส่เข้าไป jest จะนับจำนวนครั้งที่เรียกใช้งานเรื่อยๆ

import * as calculate from './calculate'

describe('spy self', () => {
  afterEach(() => {
    // restore the spy created with spyOn
    jest.restoreAllMocks()
  })

  it('Should be called add when call doubleSum', () => {
    const x = 2
    const y = 2

    const mathAddSpy = jest.spyOn(calculate, 'add')

    calculate.doubleSum(x, y)

    expect(mathAddSpy).toHaveBeenCalledTimes(1)
  })
})

calculate.test.ts


Spy other files

หากเราต้องการที่จะ spy ในไฟล์อื่นๆ ก็สามารถทำได้ดังนี้

export const add = (x: number, y: number): number => x + y

math.ts

import { add } from '../math'

export const doubleSum = (x: number, y: number): number => {
  const sum = add(x, y)
  return x + y + sum
}

calculate.ts

import { doubleSum } from './calculate'
import * as math from './math'

describe('spy', () => {
  afterEach(() => {
    // restore the spy created with spyOn
    jest.restoreAllMocks()
  })

  it('Should be called add when call doubleSum', () => {
    const x = 2
    const y = 2

    const mathAddSpy = jest.spyOn(math, 'add')

    doubleSum(x, y)

    expect(mathAddSpy).toHaveBeenCalledTimes(1)
  })

  it('Should be return 9 when call doubleSum and send 2, 2', () => {
    const x = 2
    const y = 2
    const actual = 9

    // ใช้ spyOn ในการทำ Mock / Stub ได้
    jest.spyOn(math, 'add').mockImplementation(() => 5)

    const result = doubleSum(x, y)

    expect(result).toBe(actual)
  })
})

calculate.test.ts


Spy Library

เหมือนกันกับ mock function เราสามารถ spy ตัว library เพื่อตรวจสอบการทำงานได้ด้วยเช่นกัน

ตัวอย่าง

import _ from 'lodash'

export const getUserByUserName = (keyword: string) => {
  var users = [
    { user: 'barney', birthday: '1980-01-01', age: 47 },
    { user: 'fred', birthday: '1990-01-01', age: 37 },
    { user: 'pebbles', birthday: '2000-01-01', age: 27 }
  ]

  const index = _.findIndex(users, (o) => {
    return o.user == keyword
  })

  return users[index]
}

user.test.ts

import _ from 'lodash'
import { getUserByUserName } from './user'

describe('Spy library', () => {
  it('Should be called from findIndex with spy', () => {
    const keyword = 'barney'

    const findIndexSpy = jest.spyOn(_, 'findIndex').mockReturnValue(2)

    getUserByUserName(keyword)

    expect(findIndexSpy).toHaveBeenCalled()
  })

  it('Should be return user info from keyword with spy', () => {
    const keyword = 'barney'

    jest.spyOn(_, 'findIndex').mockReturnValue(2)

    const actual = getUserByUserName(keyword)

    // expect(findIndexSpy).toHaveBeenCalled()
    expect(actual).toMatchObject({
      user: 'pebbles',
      birthday: '2000-01-01',
      age: 27
    })
  })
})

user.test.ts

อันนี้เป็นตัวอย่างง่ายๆ ในการใช้งาน spy ของ jest หากมีการใช้งานอื่นๆ เพิ่มเติม ก็สามารถเข้าไปดูใน document ของ jest ได้เหมือนเดิม