Bỏ qua để đến nội dung

System-wide Testing

Chương này thay đổi cách bạn nghĩ về testing. Thay vì test từng hàm nhỏ (unit test truyền thống), hãy test hành vi của cả hệ thống.

Cách phổ biến: mock mọi dependency, test từng class riêng lẻ.

// Unit test truyền thống — mock TutorAPI
func testCourseAPI() {
let mockTutorAPI = MockTutorAPI()
let courseAPI = CourseAPI(tutorAPI: mockTutorAPI)
// Test CourseAPI với mock
}

Vấn đề:

  • Test quá gắn chặt với implementation thay vì behavior.
  • Refactor một class → hàng loạt test gãy, dù behavior không đổi.
  • Phải maintain cả code thật lẫn hàng đống mock object.

2. System-wide Testing: Mock ở tầng thấp nhất

Phần tiêu đề “2. System-wide Testing: Mock ở tầng thấp nhất”

Thay vì mock từng dependency:

  • Khởi tạo toàn bộ hệ thống thật (CourseAPI → TutorAPI → API → Network).
  • Chỉ mock ở biên ngoài cùng — stub network response.
// System-wide test — chỉ mock network response
func testLoadCourse() async {
let stubbedNetwork = StubbedNetwork(response: fakeCourseJSON)
let api = API(network: stubbedNetwork)
let tutorAPI = TutorAPI(api: api)
let courseAPI = CourseAPI(tutorAPI: tutorAPI)
let course = try await courseAPI.loadCourse()
XCTAssertEqual(course.tutor.name, "Caleb Davis")
}

Vì test chỉ biết về input (network response) và output (kết quả), bạn tự do:

  • Đổi tên class
  • Tách/gộp class
  • Thay đổi data flow bên trong

… mà test vẫn pass, miễn behavior không thay đổi.

Test chạy gần giống app thật. Bạn phát hiện được lỗi integration — thứ mà unit test truyền thống thường bỏ sót.

Chỉ cần mock network layer (hoặc database layer). Không cần tạo MockTutorAPI, MockCourseService, MockStore… cho từng class.

Mock ở boundary thấp nhất có thể:

  • ✅ Stub network response (HTTP level)
  • ✅ Stub database query
  • ❌ Mock từng class trung gian

Ngoại lệ: Nếu một dependency thực sự chậm hoặc không ổn định (payment gateway, push notification), hãy mock nó. Nhưng đây là ngoại lệ, không phải mặc định.

Unit test truyền thống System-wide test
Tốc độ Nhanh hơn Chậm hơn đôi chút
Refactor safety Thấp — test dễ gãy Cao — test theo behavior
Mock maintenance Rất nhiều mock Ít mock
Phát hiện lỗi integration Không

Kết luận: Đừng test implementation — hãy test behavior. Mock ở tầng thấp nhất có thể, để test giống với cách app chạy thật. Khi refactor, bạn sẽ biết ơn điều này.