Tìm hiểu về Jestjs, viết unit test cho javascript
Jestjs là một JavaScript Testing Framework khá là dễ sử dụng và cài đặt, tuy nhiên vẫn đầy đủ tính năng để bạn có thể sử dụng :clap: Bài viết này mình xin giới thiệu một số tính năng cơ bản của jest cùng với một số ví dụ.
Cài đặt
Cài đặt Jest khá đơn giản:
yarn add --dev jest
hoặc
npm install --save-dev jest
Sau đó thêm đoạn code sau vào file package.json:
{
"scripts": {
"test": "jest"
}
}
Tiếp theo mình có ví dụ một file test: math.js
function sum(a, b) {
return a + b;
}
const MathJS = {
sum,
};
module.exports = MathJS;
Để viết test cho file trên mình tạo file test/math.test.js
, đuôi file là test.js sẽ nói cho jest biết đây là file test của bạn.
const MathJS = require("../math");
it("Adds 1 + 1 to equals 2", () => {
expect(MathJS.sum(1, 1)).toBe(2);
});
Sau đó chạy yarn test
hoặc npm run test
.
Các Matchers trong Jest
Ở trong đoạn code trên:
expect(MathJS.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:
a = {};
b = {};
a === b;
=> false
Còn .toEqual()
theo như Jest sẽ lần lượt kiểm tra tất các trường của Object, hoặc mảng để so sánh.
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ạitoBeUndefined
.toBeTruthy
so sánh với giá trị true.toBeFalsy
so sánh với giá trị false.
Numbers
it("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ố thập phân, bạn nên sử dụng toBeCloseTo
:
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.
});
String
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);
});
Exceptions
Để kiểm tra một lỗi có thể xảy ra bạn có thể sử dụng toThrow
:
function compileAndroidCode() {
throw new ConfigError("you are using the wrong JDK");
}
test("compiling android goes as expected", () => {
expect(compileAndroidCode).toThrow();
expect(compileAndroidCode).toThrow(ConfigError);
// You can also use the exact error message or a regexp
expect(compileAndroidCode).toThrow("you are using the wrong JDK");
expect(compileAndroidCode).toThrow(/JDK/);
});
Một số ví dụ
Test một action trong redux
const CHANGE_EMAIL = "CHANGE_EMAIL";
function changeEmail(email) {
return {
type: CHANGE_EMAIL,
email,
};
}
it("should render type and email of change email action", () => {
const email = "test@tt.com";
const expected = {
type: CHANGE_EMAIL,
email,
};
expect(changeEmail(email)).toEqual(expected);
});
Test một event trong Jquery
it("should fire a alert", () => {
const alert = jest.fn();
document.body.innerHTML =
"<div>" +
' <span id="username" />' +
' <button id="button" />' +
"</div>";
$("#button").click(() => {
alert("click");
});
$("#button").click();
expect(alert).toBeCalled();
// the mock function is called one time
expect(alert.mock.calls.length).toBe(1);
// The first argument of the first call to the function was click
expect(alert.mock.calls[0][0]).toBe("click");
});
Bạn có thể thấy const alert = jest.fn();
. Đây là một tính năng trong Jest giúp bạn mock một function. Hay mô phỏng lại hàm cần test.
Test với module axios
const axios = require("axios");
jest.mock("axios", () => ({
get: jest.fn().mockResolvedValue({ data: { message: "hello" } }),
}));
test("mock axios.get", async () => {
const response = await axios.get("https://test.com/t/1");
expect(response.data).toEqual({ foo: "bar" });
});
Trong ví dụ này mình đã mock module axios, và đặt giá trị trả về cho hàm get. Như vậy khi test bạn sẽ không cần phải gửi request thật, tránh mất thời gian. Các module khác bạn cũng có thể làm cách tương tự.