Test asynchronous code và mocking với Jest
Mở đầu
Ở phần trước tôi đã giới thiệu cơ bản về cách cài đặt cũng như cách kiểm tra xem code của mình có đúng như kết quả mong đợi. Phần này tôi sẽ giới thiệu các kỹ thuật liên quan đến Integration test. Cùng bắt đầu thôi!
1.Testing asynchronous code
Bất đồng bộ trong Javascript có 2 loại cơ bản là: Callbacks và Promises. Chúng ta sẽ lần lượt tìm hiểu cách viết test với các loại này như thế nào.
Callbacks
Cùng xem ví dụ sau để hiểu rõ hơn
//uppercase.js
function uppercase(str, callback) {
callback(str.toUpperCase())
}
module.exports = uppercase
//uppercase.test.js
const uppercase = require('./src/uppercase')
test(`uppercase 'test' to equal 'TEST'`, (done) => {
uppercase('test', (str) => {
expect(str).toBe('TEST')
done()
}
})
Ở file uppercase.js
viết hàm thực hiện đổi str
truyền vào sang chữ viết hoa. Để có thể kiểm tra xem tham số test
truyền vào đã được viết hoa hay chưa, ta phải đợi call back
được gọi, bằng cách gọi đến hàm done()
Promises
Với functions mà trả về một promises
, đầu tiên chúng ta return về promises rồi mới tiến hành so sánh. Ví dụ:
//uppercase.js
const uppercase = str => {
return new Promise((resolve, reject) => {
if (!str) {
reject('Empty string')
return
}
resolve(str.toUpperCase())
})
}
module.exports = uppercase
//uppercase.test.js
const uppercase = require('./uppercase')
test(`uppercase 'test' to equal 'TEST'`, () => {
return uppercase('test').then(str => {
expect(str).toBe('TEST')
})
})
// Trường hợp promises bị reject
test(`uppercase 'test' to equal 'TEST'`, () => {
return uppercase('').catch(e => {
expect(e).toMatch('Empty string')
})
})
Async/await
Test function mà return về promises, chúng ta cũng có thể sử dụng async/await. Với cách này trông code sẽ đơn giản, và ngắn gọn hơn.
//uppercase.test.js
const uppercase = require('./uppercase')
test(`uppercase 'test' to equal 'TEST'`, async () => {
const str = await uppercase('test')
expect(str).toBe('TEST')
})
2.Mocking
Trong khi test, mocking cho phép bạn test các function liên quan đến:
- Database
- Network requests
- Truy cập đến các File
Sử dụng mock, bạn có thể kiểm tra xem module function
đã được gọi chưa và tham số nào được sử dụng với:
expect().toHaveBeenCalled()
: kiểm tra xemspied function
đã được gọi chưaexpect().toHaveBeenCalledTimes()
: đém số lầnspied function
được gọi.expect().toHaveBeenCalledWith()
: kiểm tra function được gọi với tập các parameter chỉ định.expect().toHaveBeenLastCalledWith()
: kiểm tra các tham số truyền vào lần cuối đã được gọi chưa.
Mock an entire package
Jest cung cấp một cách dễ dàng để mock entire package
. Tạo folder __mocks__
trong project root, trong folder này tạo file js
cho mỗi package mà bạn muốn sử dụng. Ví dụ mock log function của package ta làm như sau: Tạo file __mocks__/mathjs.js
và thêm đoạn code sau:
module.exports = {
log: jest.fn(() => 'test')
}
Thêm các function mà bạn muốn mock như sau:
const mathjs = require('mathjs')
test(`The mathjs log function`, () => {
const result = mathjs.log(10000, 10)
expect(result).toBe('test')
expect(mathjs.log).toHaveBeenCalled()
expect(mathjs.log).toHaveBeenCalledWith(10000, 10)
})
Mock a single function
Sử dụng `jest.fn()` để mock một function
const mathjs = require('mathjs')
mathjs.log = jest.fn(() => 'test')
test(`The mathjs log function`, () => {
const result = mathjs.log(10000, 10)
expect(result).toBe('test')
expect(mathjs.log).toHaveBeenCalled()
expect(mathjs.log).toHaveBeenCalledWith(10000, 10)
})
Tham khảo
https://jestjs.io/docs/en/getting-started
https://callstack.com/blog/testing-react-native-with-the-new-jest-part-1-snapshots-come-into-play/#.12zbnbgwc