So Sánh Ba Cơ Chế Kiểm Tra Trong Ứng Dụng NestJS
Chào các bạn! Trong bài viết trước, mình đã cung cấp một cái nhìn tổng quát về các cơ chế kiểm tra trong NestJS. Hôm nay, mình sẽ đi sâu vào ba cơ chế chính: Unit Test, Integration Test và End-to-End (e2e) Test. Bạn có biết những cơ chế này khác nhau như thế nào và khi nào thì cần sử dụng chúng trong dự án của bạn? Hãy theo dõi bài viết dưới đây nhé!
1. Unit Test
- Mục tiêu: Kiểm tra logic của từng thành phần riêng lẻ như class, function hoặc module.
- Phạm vi: Chỉ kiểm tra một đơn vị code cụ thể và sử dụng mock cho tất cả các dependencies.
- Đặc điểm:
- Tập trung vào logic bên trong của từng thành phần.
- Thời gian thực hiện nhanh, dễ viết, và không phụ thuộc vào môi trường bên ngoài.
- Sử dụng mock để giả lập các dependencies.
- Ví dụ: Kiểm tra xem
UsersService
có hoạt động đúng khi sử dụng repository đã được mock.
Code Ví Dụ:
typescript
describe('UsersService', () => {
let service: UsersService;
let mockRepository: Partial<UsersRepository>;
beforeEach(() => {
mockRepository = {
findById: jest.fn((id) => `Mocked User ${id}`),
};
service = new UsersService(mockRepository as UsersRepository);
});
it('should return user by ID', () => {
const result = service.getUserById(1);
expect(result).toBe('Mocked User 1');
expect(mockRepository.findById).toHaveBeenCalledWith(1);
});
});
2. Integration Test
- Mục tiêu: Kiểm tra sự tương tác giữa các thành phần trong module như controller, service và repository.
- Phạm vi: Kiểm tra nhiều thành phần cùng hoạt động, thường không bao gồm kết nối cơ sở dữ liệu thực.
- Đặc điểm:
- Không mock tất cả dependencies mà sử dụng các phiên bản thực để đảm bảo các thành phần tích hợp đúng cách.
- Ví dụ: Kiểm tra xem
UsersController
có trả về đúng dữ liệu khi gọiUsersService
.
Code Ví Dụ:
typescript
describe('UsersController', () => {
let controller: UsersController;
let service: UsersService;
beforeEach(async () => {
const module = await Test.createTestingModule({
controllers: [UsersController],
providers: [UsersService, UsersRepository],
}).compile();
controller = module.get<UsersController>(UsersController);
service = module.get<UsersService>(UsersService);
});
it('should return user by ID', async () => {
jest.spyOn(service, 'getUserById').mockResolvedValue('User 1');
const result = await controller.getUserById(1);
expect(result).toBe('User 1');
});
});
3. End-to-End (e2e) Test
- Mục tiêu: Kiểm tra toàn bộ quy trình của ứng dụng từ client đến backend, bao gồm cả cơ sở dữ liệu thực.
- Phạm vi: Kiểm tra hệ thống như một ứng dụng hoàn chỉnh và toàn diện.
- Đặc điểm:
- Không mock bất kỳ thành phần nào, yêu cầu môi trường thực tế, ví dụ: server phải chạy và kết nối cơ sở dữ liệu.
- Thời gian thực hiện chậm hơn nhưng đảm bảo rằng toàn bộ ứng dụng hoạt động như mong đợi.
- Ví dụ: Kiểm tra API
/users/:id
có trả về đúng dữ liệu từ database.
Code Ví Dụ:
typescript
import * as request from 'supertest';
describe('Users (e2e)', () => {
let app: INestApplication;
beforeAll(async () => {
const module = await Test.createTestingModule({
imports: [UsersModule],
}).compile();
app = module.createNestApplication();
await app.init();
});
it('GET /users/:id', async () => {
const response = await request(app.getHttpServer())
.get('/users/1')
.expect(200);
expect(response.body).toEqual({ id: 1, name: 'User 1' });
});
afterAll(async () => {
await app.close();
});
});
So Sánh Các Cơ Chế Kiểm Tra
Tiêu chí | Unit Test | Integration Test | End-to-End Test |
---|---|---|---|
Mục tiêu | Kiểm tra logic đơn lẻ | Kiểm tra tương tác giữa các thành phần | Kiểm tra toàn bộ ứng dụng |
Phạm vi | Rất nhỏ (một class hoặc function) | Module hoặc nhóm component | Hệ thống hoàn chỉnh |
Dependencies | Được mock | Một số thực, một số mock | Sử dụng thực tế |
Tốc độ | Nhanh | Trung bình | Chậm |
Độ phức tạp | Thấp | Trung bình | Cao |
Khi nào sử dụng? | Để kiểm tra logic cụ thể nhanh chóng | Đảm bảo các thành phần hoạt động đúng khi tích hợp | Kiểm tra toàn bộ hệ thống trước khi phát hành |
Khi Nào Nên Sử Dụng Mỗi Loại Test?
-
Unit Test:
- Dùng để kiểm tra logic cụ thể (ví dụ: tính toán, xử lý dữ liệu).
- Thích hợp cho việc viết nhiều lần bởi vì tốc độ thực hiện nhanh và dễ viết.
-
Integration Test:
- Đảm bảo rằng các thành phần hoạt động đúng cũng như tích hợp với nhau.
- Thường được viết cho controller để kiểm tra toàn bộ logic của module.
-
End-to-End Test:
- Kiểm tra hệ thống trong môi trường thực tế trước khi phát hành.
- Sử dụng ít hơn do tốc độ chậm và yêu cầu môi trường phức tạp.
Tóm Lại
- Unit Tests: Kiểm tra nhanh, tập trung vào logic nhỏ.
- Integration Tests: Đảm bảo các module hoạt động đúng với nhau.
- End-to-End Tests: Đảm bảo toàn bộ hệ thống hoàn chỉnh không có lỗi lớn.
Việc kết hợp hợp lý cả ba loại kiểm tra sẽ giúp đảm bảo chất lượng cao nhất cho ứng dụng của bạn và giúp bạn phát hiện lỗi sớm hơn trong quá trình phát triển.
Liên Quan
[Thông tin thêm về NestJS Testing] (https://chatgpt.com/share/67775eed-5a40-8013-b24c-73a7c4bc13be) - Bạn có thể theo dõi bài viết gốc của mình tại đây: NestJS Testing cơ bản #nestjs #testing #backend
source: viblo