0
0
Lập trình
Hưng Nguyễn Xuân 1
Hưng Nguyễn Xuân 1xuanhungptithcm

Hướng Dẫn Kiểm Thử Class Bằng Jest: Tìm Hiểu Về Spy Trong Test Double

Đăng vào 3 tuần trước

• 6 phút đọc

Phần 4: Cách Kiểm Thử Class Với Jest

Trong phần cuối cùng của chuỗi bài viết "Tất cả về kiểm thử đơn vị với Jest", mình sẽ hướng dẫn các bạn cách viết kiểm thử cho class và cho các bạn thấy sức mạnh của spy trong Test Double.


Giới Thiệu

Chúng ta đã thực hiện phần lớn các khía cạnh quan trọng của kiểm thử đơn vị, và bài viết này sẽ tổng kết lại series. Hãy cùng bắt đầu nhé! 😆 Các bạn có thể tham khảo toàn bộ source code cho phần này ở đây.

Thiết Lập Môi Trường

Ở phần này, mình sẽ xây dựng một lớp Dog để có thể kiểm thử nó. Đầu tiên, hãy gõ lệnh sau trong thư mục gốc của dự án:

Copy
$ pwd
/Users/tienminh/Documents/testing_with_jest
$ touch Dog.js

Mở file Dog.js và viết mã sau:

Copy
class Dog {
  constructor(name, breed, age) {
    this.name = name;
    this.breed = breed;
    this.age = age;
    this.energyLevel = 10;
  }

  bark() {
    console.log(`${this.name} barks: Woof woof!`);
  }

  fetch() {
    if (this.energyLevel > 0) {
      console.log(`${this.name} is fetching.`);
      this.energyLevel -= 2;
    } else {
      console.log(`${this.name} is too tired to fetch.`);
    }
  }

  describe() {
    console.log(`${this.name} is a ${this.age}-year-old ${this.breed}.`);
  }
}

module.exports = Dog;

Giải Thích Về Các Hàm

  • constructor: phương thức khởi tạo cho đối tượng Dog.
  • bark: phương thức mô tả tiếng sủa của chó.
  • fetch: phương thức này hoạt động dựa trên mức năng lượng của chó.
  • describe: phương thức mô tả về chú chó, bao gồm tên, tuổi và giống.

Cách Kiểm Thử Class Với Jest

Đầu tiên, cần tạo một file kiểm thử cho class Dog, thực hiện lệnh sau:

Copy
$ touch Dog.spec.js

1. Kiểm Thử Class Với Jest

Để kiểm thử cho class, chúng ta sẽ sử dụng assertion để kiểm tra sự định nghĩa của static methodinstance method.

  • Việc kiểm thử class tương tự như kiểm thử module, khác biệt chính là chúng ta cần khởi tạo nó trước khi kiểm thử.
  • Jest cung cấp cho chúng ta jest.spyOn() để kiểm thử dễ dàng hơn.
javascript Copy
// Dog.spec.js
const Dog = require("./Dog.js");

describe("Dog", () => {
    let dog = new Dog('Buddy', 'Golden Retriever', 3);
    const barkSpy = jest.spyOn(dog, "bark");
    const fetchSpy = jest.spyOn(dog, "fetch");
    const describeSpy = jest.spyOn(dog, "describe");

    describe(".bark", () => {
        it ("defines a function", () => {
            expect(typeof dog.bark).toBe("function");
        })
    })

    describe(".fetch", () => {
        it ("defines a function", () => {
            expect(typeof dog.fetch).toBe("function");
        })
    })

    describe(".describe", () => {
        it ("defines a function", () => {
            expect(typeof dog.describe).toBe("function");
        })
    })
})

Giải Thích:

  • Ở đây chúng ta chỉ kiểm tra xem các instance method có được khởi tạo hay không và có kiểu như nào.

Lưu Ý:

  • Đến thời điểm này, chúng ta mới chỉ kiểm thử lớp interface, chưa đi sâu vào việc thực thi của từng instance method.

Tiếp theo, chúng ta sẽ kiểm thử các phương thức trong class.

2. Kiểm Thử Các Phương Thức Trong Class

javascript Copy
// Dog.spec.js
const Dog = require("./Dog.js");

describe("Dog", () => {
    let dog = new Dog('Buddy', 'Golden Retriever', 3);
    const barkSpy = jest.spyOn(dog, "bark");
    const fetchSpy = jest.spyOn(dog, "fetch");
    const describeSpy = jest.spyOn(dog, "describe");
    const consoleSpy = jest.spyOn(console, "log");

    afterEach(() => {
        consoleSpy.mockClear();
    })

    describe(".bark", () => {
        it ("return undefined and console log when call", () => {
            expect(dog.bark()).toBeUndefined();
            expect(consoleSpy).toHaveBeenCalledWith("Buddy barks: Woof woof!");
            expect(barkSpy).toHaveBeenCalled();
        })
    })

    describe(".fetch", () => {
        describe("energy", () => {
            it ("greater than 0", () => {
                expect(dog.fetch()).toBeUndefined();
                expect(dog.energyLevel).toBe(8);
                expect(consoleSpy).toHaveBeenCalledWith("Buddy is fetching.");
                expect(fetchSpy).toHaveBeenCalled();
            })

            it ("less than 0", () => {
                // Arrange
                dog.energyLevel = 0;

                // act + assertion
                expect(dog.fetch()).toBeUndefined();
                expect(consoleSpy).toHaveBeenCalledWith("Buddy is too tired to fetch.");
                expect(fetchSpy).toHaveBeenCalled();
            })
        })
    })

    describe(".describe", () => {
        it ("return undefined and console log when call", () => {
            expect(dog.describe()).toBeUndefined();
            expect(consoleSpy).toHaveBeenCalledWith("Buddy is a 3-year-old Golden Retriever.");
            expect(describeSpy).toHaveBeenCalled();
        })
    })
})

Điểm Cần Chú Ý:

  • Chúng ta đã sử dụng nhiều spy để kiểm thử class từ interface đến implement function.
  • Trong thực tế khi kiểm thử class, chúng ta sẽ kiểm thử các hàm thực thi gốc mà không thay đổi bất kỳ logic nào.
  • Sự khác biệt giữa kiểm thử modulekiểm thử class:
    • Kiểm thử module cần kiểm thử theo hành vi của nó, đồng thời có thể mock các phụ thuộc bên ngoài.
    • Kiểm thử class yêu cầu khởi tạo object của class trước khi thực hiện kiểm thử cho các instance method.

Lưu Ý:

  • Sức mạnh của spy thể hiện rõ trong việc kiểm thử class.

Kết Luận

  • Sau khi hoàn thành 4 phần, chúng ta đã tìm hiểu về mô hình AAA, cũng như các khái niệm như stub, spy, mock, dummy objectfake object.
  • Việc sử dụng mockdummy object dường như không phổ biến và có thể coi là ít sử dụng.
  • Chỉ với stubspy, chúng ta có thể thực hiện hầu hết các unit test.
  • Tuy nhiên, khi viết unit test, việc hiểu rõ các thành phần này giúp cho mã của chúng ta trở nên hiệu quả và tin cậy hơn.
  • Chúng ta hãy cố gắng viết unit test không chỉ hiệu quả mà còn hợp lý, từ đó nâng cao độ tin cậy cho ứng dụng.
  • Cảm ơn các bạn đã theo dõi toàn bộ series này! 🙇🏼‍♂️

Tài Liệu Tham Khảo

Gợi ý câu hỏi phỏng vấn
Không có dữ liệu

Không có dữ liệu

Bài viết được đề xuất
Bài viết cùng tác giả

Bình luận

Chưa có bình luận nào

Chưa có bình luận nào