# Tài Liệu Độ Phủ Kiểm Thử

## Tổng Quan

Thư mục này chứa tài liệu toàn diện hướng dẫn viết kiểm thử cho **17 tệp nguồn chưa được kiểm thử** thuộc các module inquiries, leads và reviews của GoodGo Platform API.

## Các Tệp Bao Gồm

### 1. **TEST_COVERAGE_ANALYSIS.md** (1.841 dòng, 55KB)
   - **Triển khai đầy đủ** của tất cả 17 tệp chưa được kiểm thử
   - Mã nguồn hoàn chỉnh cho từng tệp
   - Giải thích chi tiết chức năng của từng phương thức
   - Các kịch bản kiểm thử cho từng thành phần
   - Tham chiếu các mẫu kiểm thử từ các tệp kiểm thử hiện có
   - Mẫu và ví dụ kiểm thử toàn diện

### 2. **TEST_COVERAGE_QUICK_REFERENCE.md** (301 dòng, 9,1KB)
   - Hướng dẫn tra cứu nhanh cho tất cả 17 tệp
   - Danh sách kiểm tra theo loại tệp (repositories, VOs, DTOs, controllers)
   - Các kịch bản kiểm thử theo module
   - Ma trận ưu tiên (critical, high, medium)
   - Thứ tự thực thi kiểm thử được khuyến nghị
   - Mẫu thiết lập mock
   - Các công thức quan trọng cần xác minh

### 3. **TEST_TEMPLATES.md** (500+ dòng)
   - Mẫu kiểm thử sẵn dùng cho:
     - Kiểm thử Repository
     - Kiểm thử Value Object
     - Kiểm thử DTO
     - Kiểm thử Controller
   - Kiểm thử helper cho tính toán phân trang
   - Kiểm thử helper cho công thức tổng hợp
   - Kiểm thử helper xác thực DTO

## Bắt Đầu Nhanh

### Để có cái nhìn tổng quan nhanh:
1. Đọc **Quick Reference** trước (5–10 phút)
2. Xác định loại tệp bạn muốn kiểm thử
3. Chuyển đến mục tương ứng trong **TEST_TEMPLATES.md**
4. Sao chép mẫu và điều chỉnh cho tệp của bạn

### Để hiểu sâu hơn:
1. Bắt đầu với tổng quan **Quick Reference**
2. Đọc phần module liên quan trong **TEST_COVERAGE_ANALYSIS.md**
3. Sử dụng **TEST_TEMPLATES.md** làm hướng dẫn triển khai
4. Tham chiếu các mẫu kiểm thử ví dụ trong tài liệu Analysis

## Tổ Chức Tệp Theo Module

### Module Inquiries (4 tệp)
```
✗ prisma-inquiry.repository.ts     — 6 phương thức, phân trang, quan hệ
✗ inquiries.controller.ts           — 4 endpoint, guards
✗ create-inquiry.dto.ts             — 3 validation
✗ list-inquiries.dto.ts             — 2 validation (phân trang)
```

### Module Leads (6 tệp)
```
✗ prisma-lead.repository.ts         — 6 phương thức, tổng hợp thống kê
✗ lead-score.vo.ts                  — Xác thực khoảng giá trị (0-100)
✗ leads.controller.ts               — 5 endpoint, role guards
✗ create-lead.dto.ts                — 6 validation
✗ list-leads.dto.ts                 — Enum trạng thái, phân trang
✗ update-lead-status.dto.ts         — Enum trạng thái
```

### Module Reviews (5 tệp)
```
✗ prisma-review.repository.ts       — 7 phương thức, thống kê phân phối
✗ rating.vo.ts                      — Xác thực khoảng số nguyên (1-5)
✗ reviews.controller.ts             — 5 endpoint, xác thực hỗn hợp
✗ create-review.dto.ts              — 4 validation
✗ list-reviews.dto.ts               — 2 lớp DTO, phân trang
```

## Mức Độ Ưu Tiên Kiểm Thử

### 🔴 CRITICAL (Logic Nghiệp Vụ)
1. **PrismaReviewRepository.getStats()** — Tính toán phân phối phức tạp
2. **PrismaLeadRepository.getStatsByAgent()** — Công thức tỷ lệ chuyển đổi
3. **Rating.vo** — Phải xác thực chỉ số nguyên từ 1–5
4. **LeadScore.vo** — Phải xác thực khoảng 0–100

**Bắt đầu từ đây** — Đây là các validation quan trọng nhất cho nghiệp vụ

### 🟡 HIGH (Tính Toàn Vẹn Dữ Liệu)
1. Các thao tác CRUD của Repository
2. Tính toán phân trang
3. Ánh xạ quan hệ (user joins, duyệt listing)
4. Điều phối command/query từ Controller

**Kiểm thử tiếp theo** — Đảm bảo tính nhất quán của dữ liệu

### 🟢 MEDIUM (Validation & Guards)
1. Xác thực trường DTO
2. Ràng buộc Enum
3. Xử lý trường tùy chọn
4. Guards xác thực/phân quyền

**Kiểm thử sau cùng** — Đây là các mối quan tâm ở tầng framework

## Lộ Trình Thực Thi Kiểm Thử

### Tuần 1: Value Objects & DTOs (8–10 tệp kiểm thử)
- [ ] LeadScore.vo.ts (1 tệp, 4–5 test case)
- [ ] Rating.vo.ts (1 tệp, 4–5 test case)
- [ ] Tất cả 10 tệp DTO (dùng mẫu, biến thể tối thiểu)

**Thời gian ước tính:** 3–5 giờ tổng cộng

### Tuần 2: Controllers (2 tệp kiểm thử)
- [ ] InquiriesController (4 endpoint + guards)
- [ ] LeadsController (5 endpoint + guards)
- [ ] ReviewsController (5 endpoint + xác thực hỗn hợp)

**Thời gian ước tính:** 2–3 giờ tổng cộng

### Tuần 3: Repositories (3 tệp kiểm thử)
- [ ] PrismaInquiryRepository (6 phương thức)
- [ ] PrismaLeadRepository (6 phương thức + tổng hợp)
- [ ] PrismaReviewRepository (7 phương thức + phân phối)

**Thời gian ước tính:** 4–6 giờ tổng cộng

### Tổng Thời Gian Ước Tính: 9–14 giờ

## Các Mẫu Kiểm Thử Quan Trọng

### Repositories
```typescript
// Mock tất cả phương thức Prisma trong beforeEach
mockPrisma = {
  [model]: { 
    findUnique: vi.fn(), 
    findMany: vi.fn(), 
    create: vi.fn(), 
    update: vi.fn(), 
    count: vi.fn() 
  }
};

// Kiểm thử luồng thành công và trường hợp lỗi
// Xác minh tính toán phân trang
// Xác minh chuyển đổi dữ liệu (toDomain)
```

### Value Objects
```typescript
// Kiểm thử các trường hợp hợp lệ
const result = ValueObject.create(validValue);
expect(result.isOk()).toBe(true);

// Kiểm thử các trường hợp không hợp lệ
const result = ValueObject.create(invalidValue);
expect(result.isErr()).toBe(true);
expect(result.unwrapErr()).toBe('error message');
```

### DTOs
```typescript
// Sử dụng validate() từ class-validator
const errors = await validate(dto);
expect(errors).toHaveLength(0); // hoặc > 0 cho trường hợp không hợp lệ

// Kiểm thử chuyển đổi kiểu với class-transformer
// Kiểm thử xử lý trường tùy chọn
```

### Controllers
```typescript
// Mock CommandBus và QueryBus
mockCommandBus.execute.mockResolvedValue(expectedResult);

// Xác minh cấu trúc command/query
const command = mockCommandBus.execute.mock.calls[0][0];
expect(command.userId).toBe(expectedUserId);
```

## Các Công Thức Quan Trọng Cần Kiểm Thử

### Phân Trang
```
skip = (page - 1) * take
totalPages = Math.ceil(total / take)
take = Math.min(limit, 100)  // Giới hạn tối đa 100
```

### Thống Kê Lead
```
conversionRate = (CONVERTED_count / total_leads) * 100  // 2 chữ số thập phân
avgScore = (sum_of_scores / non_null_count)            // 1 chữ số thập phân, null nếu không có điểm
```

### Thống Kê Review
```
averageRating = (sum_of_ratings / total_reviews)       // 1 chữ số thập phân
distribution = { 1: count, 2: count, 3: count, 4: count, 5: count }
```

## Các Câu Lệnh Import Cần Dùng

```typescript
// Tiện ích kiểm thử
import { describe, it, expect, beforeEach, vi } from 'vitest';
import { validate } from 'class-validator';
import { plainToClass } from 'class-transformer';

// Tiện ích NestJS (dùng cho kiểm thử controller)
import type { EventBus, CommandBus, QueryBus } from '@nestjs/cqrs';

// Các lớp domain
import { InquiryEntity } from './domain/entities/inquiry.entity';
import { LeadEntity } from './domain/entities/lead.entity';
import { ReviewEntity } from './domain/entities/review.entity';
import { LeadScore } from './domain/value-objects/lead-score.vo';
import { Rating } from './domain/value-objects/rating.vo';
```

## Dữ Liệu Kiểm Thử Thông Dụng

### ID Người Dùng
```
user-1, user-2, user-3, user-agent-1
```

### Trạng Thái Lead
```
NEW, CONTACTED, QUALIFIED, NEGOTIATING, CONVERTED, LOST
```

### Giá Trị Mặc Định Phân Trang
```
page: 1, limit: 20 (tối đa 100)
```

### Khoảng Đánh Giá
```
1-5 sao (chỉ số nguyên)
```

### Khoảng Điểm Lead
```
0-100 (bất kỳ số nào)
```

## Tài Liệu Tham Khảo

### Các Tệp Kiểm Thử Hiện Có (Dùng Làm Tham Chiếu)
- `src/modules/inquiries/application/__tests__/create-inquiry.handler.spec.ts` (mẫu 20 dòng)
- `src/modules/leads/application/__tests__/create-lead.handler.spec.ts` (mẫu 20 dòng)
- `src/modules/reviews/presentation/__tests__/reviews.controller.spec.ts` (mẫu 135 dòng)

### Triển Khai Đầy Đủ
Tất cả 17 triển khai tệp có trong `TEST_COVERAGE_ANALYSIS.md` với giải thích từng dòng.

## Xử Lý Sự Cố

### Vấn đề: "Cannot find module" khi mock
**Giải pháp:** Sử dụng ép kiểu `as any` cho các dependency được mock
```typescript
const repo = new PrismaInquiryRepository(mockPrisma as any);
```

### Vấn đề: Kiểm thử validation không hoạt động
**Giải pháp:** Đảm bảo dùng `plainToClass` cho các DTO có transformer
```typescript
const dto = plainToClass(CreateLeadDto, plainObject);
```

### Vấn đề: Tính toán phân trang không khớp
**Giải pháp:** Nhớ rằng limit được giới hạn ở 100
```typescript
const take = Math.min(limit, 100);  // Luôn thực hiện bước này
```

### Vấn đề: Tính toán thống kê có lỗi làm tròn
**Giải pháp:** Kiểm tra yêu cầu số chữ số thập phân:
- conversionRate: 2 chữ số thập phân (nhân với 10000, chia cho 100)
- avgScore: 1 chữ số thập phân (nhân với 10, chia cho 10)
- averageRating: 1 chữ số thập phân (nhân với 10, chia cho 10)

## Các Bước Tiếp Theo

1. **Chọn tệp bắt đầu** từ Tuần 1 (khuyến nghị LeadScore.vo trước — đơn giản nhất)
2. **Mở mẫu** tương ứng với loại tệp đó trong TEST_TEMPLATES.md
3. **Sao chép mẫu** vào vị trí tệp kiểm thử của bạn
4. **Điều chỉnh mẫu** với các import và dữ liệu cụ thể của bạn
5. **Chạy kiểm thử** và xác minh chúng đạt
6. **Chuyển sang tệp tiếp theo** theo lộ trình

## Tài Nguyên Hỗ Trợ

- Triển khai đầy đủ: Xem **TEST_COVERAGE_ANALYSIS.md**
- Tra cứu nhanh: Xem **TEST_COVERAGE_QUICK_REFERENCE.md**
- Mẫu mã: Xem **TEST_TEMPLATES.md**
- Kiểm thử tham chiếu: Xem các tệp spec hiện có trong các module

---

**Cập Nhật Lần Cuối:** 2026-04-11  
**Tổng Số Tệp Được Ghi Lại:** 17 tệp nguồn chưa được kiểm thử  
**Tổng Tài Liệu:** 2.142 dòng phân tích và mẫu  
**Thời Gian Kiểm Thử Ước Tính:** 9–14 giờ tổng cộng
