Site icon saotuvi.com

Jest là gì? Hướng dẫn cấu hình Jest với Typescript

3 buoc viet TDD

Bài viết này mình sẽ mang đến cho các bạn cái nhìn tổng quan về Jest, nếu các bạn chưa hiểu rõ về Unit Test thì nên đọc bài viết về Unit Test trước khi bắt đầu với Jest nhé.

1. Jest là gì?

Jest là một framework kiểm thử JavaScript tạo ra bởi Facebook, được thiết kế để làm cho việc viết kiểm thử trở nên dễ dàng. Ban đầu, Jest được tạo ra để kiểm thử các ứng dụng React, nhưng hiện nay được sử dụng để kiểm thử bất kỳ dự án Javascript nào.

2. TDD và BDD là gì?

Trước khi đi chi tiết vào Jest, thì mình muốn giới thiệu đến các phương pháp kiểm thử mà Jest hỗ trợ rất tốt: Test-Driven Development (TDD) và Behavior-Driven Development (BDD)

2.1 Test-Driven Development (TDD)

Test-Driven Development (TDD) là phương pháp phát triển phần mềm mà bài kiểm thử (tests) được viết trước khi viết code. TDD tập trung vào việc phát triển dựa trên yêu cầu về tính năng, và mỗi yêu cầu đó phải được kiểm thử cẩn thận để đảm bảo rằng nó được thực hiện đúng như mong đợi.

3 bước trong quy trình TDD được lặp đi lặp lại suốt quá trình phát triển phần mềm bao gồm:

  1. Red (Viết kiểm thử thất bại): bắt đầu bài kiểm thử không thành công (failing test). Bài kiểm thử này thể hiện yêu cầu mà mã cần thực hiện.
  2. Green (Viết mã để kiểm thử thành công): sau đó, viết mã tối thiểu cần thiết để bài kiểm thử thành công.
  3. Refactor (Cải tiến mã): cải tiến code, đảm bảo code sạch, tối ưu và vẫn giữ nguyên kết quả bài kiểm thử.
3 buoc viet TDD

2.2 Behavior-Driven Development (BDD)

Behavior-Driven Development (BDD) là mở rộng của TDD, tập trung vào việc phát triển phần mềm dựa trên các hành vi mong đợi của hệ thống.

Trong BDD, các bài kiểm thử được viết theo giai đoạn (scenarios):

Ví dụ với chức năng login cho bạn dễ hiểu hơn nhé:

3. Ưu và Nhược điểm của Jest

3.1 Ưu điểm của Jest

3.2 Nhược điểm của Jest

4. Tổng quan về các tính năng của Jest

4.1 Using Matchers

Dùng để kiểm tra giá trị mong muốn với giá trị hàm thực hiện.

Typescript

test('two plus two is four', () => {
  expect(2 + 2).toBe(4);  // Kiểm tra phép tính 2 + 2 có bằng 4 không
});

test('object assignment', () => {
  const data: { one: number; two?: number } = { one: 1 };
  data['two'] = 2;
  expect(data).toEqual({ one: 1, two: 2 }); //Kiểm tra trường của object có giống nhau không
});

4.2 Test Truthiness (Kiểm tra tính đúng đắn)

Khi bạn cần phân biệt các giá trị false, null, undefined để có thể đưa ra cách xử lý phù hợp.

Typescript

test('null', () => {
  const n: null = null;
  expect(n).toBeNull();  // Kiểm tra biến n là null.
  expect(n).toBeDefined();  // Kiểm tra biến n được định nghĩa.
  expect(n).not.toBeUndefined();  // Kiểm tra biến n không phải undefined.
  expect(n).not.toBeTruthy();  // Kiểm tra biến n không phải là truthy.
  expect(n).toBeFalsy();  // Kiểm tra biến n là falsy.
});

4.3 Number

Dùng để so sánh các con số với các điều kiện như lớn hơn, nhỏ hơn, bằng nhau hoặc không bằng nhau.

Typescript

test('two plus two', () => {
  const value: number = 2 + 2;
  expect(value).toBeGreaterThan(3);  // Kiểm tra giá trị lớn hơn 3.
  expect(value).toBeLessThanOrEqual(4);  // Kiểm tra giá trị nhỏ hơn hoặc bằng 4.
  expect(value).toBe(4);  // Kiểm tra giá trị bằng 4.
});

4.4 String

Dùng để kiểm tra có hoặc không có trong chuỗi

Typescript

test('there is no I in team', () => {
  expect('team').not.toMatch(/I/);  // Kiểm tra chuỗi "team" không chứa ký tự "I" không.
});

4.5 Array

Dùng để kiểm tra xem mảng có chứa phần tử không

Typescript

test('the shopping list has beer on it', () => {
  const shoppingList: string[] = ['beer', 'milk', 'bread'];
  expect(shoppingList).toContain('beer');  // Kiểm tra mảng có chứa phần tử 'beer' không.
});

4.6 Exception

Dùng để kiểm tra xem function có ném ra exception không, nội dung của exception đó

Typescript

function compileAndroidCode(): never {
  throw new Error('200Lab');
}

test('compiling android goes as expected', () => {
  expect(() => compileAndroidCode()).toThrow('200Lab');  // Kiểm tra exception
});

4.7 Callbacks

Kiểm thử các function bất đồng bộ thông qua callbacks

Typescript

function fetchData(callback: (data: string) => void): void {
  callback('peanut butter');
}

test('the data is peanut butter', (done: jest.DoneCallback) => {
  function callback(data: string) {
    expect(data).toBe('peanut butter');
    done();  // Gọi `done` để kết thúc kiểm thử khi callback được gọi.
  }
  fetchData(callback);
});

4.8 Promise

Dùng để kiểm thử các function bất đồng bộ trả về Promise

Typescript

function fetchData(): Promise<string> {
  return Promise.resolve('peanut butter');
}

test('the data is peanut butter', () => {
  return fetchData().then(data => {
    expect(data).toBe('peanut butter');  // Kiểm tra dữ liệu trả về từ promise.
  });
});

4.9 Async/Await

Sử dụng cú pháp async / await để kiểm thử code bất đồng bộ

Typescript

async function fetchData(): Promise<string> {
  return 'peanut butter';
}

test('the data is peanut butter', async () => {
  const data = await fetchData();
  expect(data).toBe('peanut butter');  // Kiểm tra giá trị trả về từ hàm không đồng bộ.
});

4.10 Mock Function

Dùng để kiểm thử hàm và các giá trị trả về

Typescript

const myMock = jest.fn().mockReturnValue('default');  // Tạo một hàm mock với giá trị trả về mặc định.

test('mock function returns default value', () => {
  expect(myMock()).toBe('default');
});

4.11 Mock Implementations

Jest cho phép mô phỏng toàn bộ triển khai của một hàm

Typescript

const myMock = jest.fn((x: number, y: number) => x + y);  // Triển khai hàm mock tùy chỉnh.

test('mock implementation of addition', () => {
  expect(myMock(1, 2)).toBe(3);
});

4.12 Testing Snapshot

Giúp đảm bảo giao diện hoặc kết quả của function không thay đổi ngoài ý muốn

Typescript

test('snapshot', () => {
  const user = { name: 'John', age: 30 };
  expect(user).toMatchSnapshot();  // Tạo snapshot và so sánh
});

4.13 Tổ chức bài kiểm thử theo nhóm

Sử dụng describe để tổ chức các bài kiểm thử theo nhóm

Typescript

describe('matching cities to foods', () => {
  test('Vancouver has sushi', () => {
    expect(true).toBe(true);
  });

  test('Toronto has poutine', () => {
    expect(true).toBe(true);
  });
});

4.14 Thiết lập và dọn dẹp môi trường

Dùng beforeAllafterAll để thiết lập, dọn dẹp môi trường một lần cho tất cả các bài kiểm thử.

Typescript

beforeAll(() => {
  console.log('Setup before all tests');
});

afterAll(() => {
  console.log('Clean up after all tests');
});

Hoặc bạn cũng có thể sử dụng beforeEachafterEach đối với mỗi bài kiểm thử

Typescript

beforeEach(() => {
  console.log('Setup before each test');
});

afterEach(() => {
  console.log('Clean up after each test');
});

5. Hướng dẫn config Jest trong dự án Typescript

5.1 Khởi tạo dự án Typescript

Bash

npm init -y
npm install ts-node typescript --save-dev
npx tsc --init

Đây là file tsconfig.json

JSON

{
  "compilerOptions": {
    "target": "es6",
    "module": "commonjs",
    "moduleResolution": "node",
    "sourceMap": true,
    "outDir": "./dist",
    "rootDir": "./src",
    "strict": true,
    "esModuleInterop": true,
    "skipLibCheck": true,
    "forceConsistentCasingInFileNames": true
  },
  "exclude": ["node_modules"]
}

5.2 Cài đặt Jest

Bash

npm install jest @types/jest ts-jest --save-dev

5.3 Cấu hình Jest

Sau khi hoàn thành việc cài đặt các thư viện cần thiết, tiến hành tạo một tệp mới jest.config.ts ở thư mục gốc của dự án.

Typescript

import type { Config } from 'jest';

const config: Config = {
  preset: 'ts-jest',
  testEnvironment: 'node',
  testMatch: ['**/*.test.ts'],
  moduleFileExtensions: ['js', 'ts'],
};

export default config;

Sau đó, tương tự với câu lệnh build bạn hãy vào lại file package.json để thêm câu lệnh "test":"jest" vào phần script nha.

JSON

{
  "name": "200lab_jest_demo",
  "version": "1.0.0",
  "description": "",
  "main": "src/index.ts",
  "scripts": {
    "build": "tsc",
    "test": "jest"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "@types/jest": "^29.5.12",
    "jest": "^29.7.0",
    "ts-jest": "^29.2.5",
    "ts-node": "^10.9.2",
    "typescript": "^5.5.4"
  }
}

5.4 Tạo mới Test case

Đầu tiên, bạn tiến hành tạo file src/math.test.ts và file src/math.ts.

Typescript

export function add(a: number, b: number): number {
  return a + b;
}

Typescript

import { add } from './math';

describe('Math functions', () => {
  test('should return 5 for add(2, 3)', () => {
    expect(add(2, 3)).toBe(5);
  });

  test('should return 0 for add(-2, 2)', () => {
    expect(add(-2, 2)).toBe(0);
  });
});

Cuối cùng, hãy chạy thử npm test và xem kết quả trên terminal

6. Kết luận

Qua bài viết này, hy vọng bạn sẽ hiểu hơn về Jest, hiểu biết cơ bản về việc sử dụng Jest trong dự án Typescript của mình. Trong các dự án lớn, bạn có thể tích hợp thêm husky hoặc eslint.

Một vài chủ đề thú vị có thể bạn quan tâm:

Exit mobile version