Jest là gì?
Với nodejs thì chúng ta có các cựu chiến binh như mocha, Jasmime, ... Nhưng đó là trước đây, còn bây giờ người ta chuộm dùng jest hơn.
Thì Jest và Ava nó đang như những đứa mới dậy thì lớn nhanh như thổi vì chính sự đơn giản và hiệu quả.
Bài viết này sẽ hướng dẫn về jest và đặc biệt là dùng trong typascript.
TDD và BDD là gì?
TDD (Test Driven Development) Cái này kiểu như bạn làm chuẩn là phải viết Unit test trước rồi mới viết chương trình.
BDD(Behavior Driven Development) là kiểu viết logic trước rồi mới viết test.
Unit test mà không có jest
Khi chưa có sử dụng 1 công cụ nào thì để test được tôi kỳ vọng bạn nên có 2 function: 1 alf function để chạy test, 1 function để so sánh kết quả đầu ra mong đợi. Vậy, Tôi sẽ tạo ra 2 function gồm:
// test
function test (message, functionTesting) {
try {
functionTesting()
console.log(`${message}: Kết thúc quá trình test.`)
} catch (err) {
console.error(`${message}: Gặp lỗi - ${err.message}`)
}
}
// expect
function expect (value) {
return {
toBe: (toBeValue) => {
if (toBeValue === value) {
console.log('Pass!')
} else {
throw new Error('Error!')
}
}
}
}
Ok bây giừo bạn muốn check 1 cái hàm có tên findFirstOdd thì bạn dùng như sau:
function findFirstOdd (arr) {
return arr.find( item => (parseInt(item) || 0) % 2 == 1 )
}
test('findFirstOdd', () => {
expect(findFirstOdd([ 0 , 2, 4, 3 ])).toBe(3) // pass hay không?
})
Kết quả:
Pass!
findFirstOdd: Kết thúc quá trình test.
Sử dụng Unit test với Jest
Setup
npm install --save-dev jest
Notes: --save-dev
chạy cho việc quá trình build code, còn --save
được sử dụng để cài đặt package cần thiết để khi ứng dụng chạy.
Bước thứ ba là chạy lệnh:
để tạo tệp cấu hình jest là jest.config.js
. Các lựa chọn của tôi như sau:
Và mình chọn các option như sau:
The following questions will help Jest to create a suitable configuration for your project
✔ Would you like to use Jest when running "test" script in "package.json"? … yes
✔ Would you like to use Typescript for the configuration file? … no
✔ Choose the test environment that will be used for testing › node
✔ Do you want Jest to add coverage reports? … yes
✔ Which provider should be used to instrument code for coverage? › v8
✔ Automatically clear mock calls, instances and results before every test? … yes
✏️ Modified /testing/package.json
📝 Configuration file created at /testing/jest.config.js
Và package.json sẽ có cái test script như sau:
Giờ test thì như sau:
touch index.test.js # tạo file index.test.js
tạo chương trình
Bạn muốn test bạn phải biết bạn test cái gì đúng không. Giống kiểu bạn phải có chương trình hoặc ít nhất là vài cái function. Vậy chúng ta giả sử có 1 file index.js với nội dung như sau:
const findFirstOdd = (arr) => {
return arr.find((item) => item % 2 == 1);
}
function sum(a, b) {
return a + b;
}
module.exports = {
findFirstOdd,
sum
}
Test function
Tạo file index.test.js với nội dung như sau:
const { findFirstOdd, sum } = require("./index")
it('findFirstOdd', () => {
expect(findFirstOdd([ 0 , 2, 4, 3 ])).toBe(3)
})
it('Adds 1 + 1 to equals 2', () => {
expect(sum(1, 1)).toBe(2);
})
Exec test
Chạy lệnh sau dưới terminal:
Kết quả:
Ok. 😄
Các Matchers trong Jest
Ở trong đoạn code trên bạn dùng là
expect(sum(1, 1)).toBe(2)
.toBe()
chính là một matcher trong jest. Nó giống như phép so sánh bằng bình thường vậy. Ví dụ:
expect(result).toBe(2);
expect(result).toBe(true);
expect(result).toBe({a: 1, b: 2});
Tuy nhiên khi so sánh một Object bạn nên sử dụng .toEqual()
Lý do là vì .toBe
thực tế sử dụng ===
để so sánh và đưa ra kết quả. Và chúng ta đều biết trong javascript:
const a = {};
const b = {};
a === b;
=> false
Vì vậy thay vì viết:
expect(result).toBe({a: 1, b: 2});
Hãy viết:
expect(result).toEqual({a: 1, b: 2});
Ngoài ra còn các matchers khác:
Truthiness
toBeNull
so sánh với giá trị null
.toBeUndefined
so sánh với giá trị undefined
.toBeDefined
là hàm cho kết quả ngược lại toBeUndefined
.toBeTruthy
so sánh với giá trị true.toBeFalsy
so sánh với giá trị false.
Numbers
test('two plus two', () => {
const value = 2 + 2;
expect(value).toBeGreaterThan(3);
expect(value).toBeGreaterThanOrEqual(3.5);
expect(value).toBeLessThan(5);
expect(value).toBeLessThanOrEqual(4.5);
// toBe and toEqual are equivalent for numbers
expect(value).toBe(4);
expect(value).toEqual(4);
});
Đối với số kiểu dữ liệu float hay double thì bạn nên dùng toBeCloseTo
thay vì dùng toEqual
.
it('adding floating point numbers', () => {
const value = 0.1 + 0.2;
//expect(value).toBe(0.3); This won't work because of rounding error
expect(value).toBeCloseTo(0.3); // This works.
});
Strings
Bạn có thể kiểm tra một đoạn văn bản với regular expressions bằng toMatch
:
it('there is no I in team', () => {
expect('team').not.toMatch(/I/);
});
it('but there is a "stop" in Christoph', () => {
expect('Christoph').toMatch(/stop/);
});
Array
Để kiểm tra giá trị có trong một mảng, bạn có thể dùng toContain:
const array = [1, 2, 10, 1000];
it('array has 1000 on it', () => {
expect(array).toContain(1000);
});
Bạn có thể tham khảo các matcher của jest ở đây: https://jestjs.io/docs/using-matchers
Jest với typescript
jest là module dùng để test javascript 1 cách nhanh gọn hiệu quả của Facebook, còn với ts-jest bạn hoàn toàn có thể sử dụng với typescript.
Để cài đặt thì bạn dùng lệnh sau trong terminal
npm install --save-dev jest @types/jest ts-jest typescript
# hoặc yarn
yarn add --dev jest @types/jest ts-jest typescript
Nếu bạn có nhu cầu tái sử dụng nhiều nơi thì bạn hoàn toàn có thể cài jest dưới dạng global:
Sau đó bạn nhớ là bên jest test javascript bạn dùng npx jest --init thì bên ts-jest bạn có thể dùng:
Ngoài ra nếu project bạn chưa cấu hình typescript để có file tsconfig.json thì bạn cứ dùng lệnh :
tsc --init # nếu đã có typescript global
# hoặc
npx --package typescript tsc --init
Sửa lại file tsconfig.json 1 chút như sau: mở comment: sourceMap: true và mở comment outDir sửa thành ./dist:
Xong. Giờ viết code trong folder src
vào folder src tạo file index.ts với nội dung:
// touch ./src/index.ts
export function findFirstOdd (arr : number[]) {
return arr.find((item) => item % 2 == 1)
}
Tạo thêm file index.test.ts để thực hiện test :
// touch ./src/index.test.ts
import { findFirstOdd } from "./index"
describe("Find", () => {
it('findFirstOdd', () => {
expect(findFirstOdd([ 0 , 2, 4, 3 ])).toBe(3)
})
});
Kết quả: