Mock verify interactions (assertions), Stub cung cấp canned responses, Spy observe real implementation, Fake có working implementation đơn giản — overcrowded mocks là code smell, thường báo hiệu SRP violation.
- Test doubles là các loại replacements cho real dependencies trong tests — Martin Fowler phân loại trong 'Mocks Aren't Stubs'.
- Dummy: placeholder object được pass vào nhưng không bao giờ thực sự được dùng — ví dụ pass null hoặc empty object để fulfill parameter requirement.
- Stub: trả về pre-configured responses cho calls — không verify interactions, chỉ provide canned answers; ví dụ stub database trả về fixed user object.
- Mock: pre-programmed với expectations về calls mà nó sẽ nhận — verify những interactions này xảy ra; jest.fn() là mock vì có thể assert toHaveBeenCalledWith(); test fail nếu expected calls không xảy ra.
- Spy: wrap real implementation, record calls — jest.spyOn() by default calls real method, ghi lại arguments; có thể override với mockImplementation khi cần.
- Fake: có working implementation đơn giản hơn real — fake in-memory database (Map<id, entity>), fake email service (lưu emails vào array thay vì gửi thật), fake message queue.
- Practical guidance: dùng Stub khi cần control return values; Mock khi muốn verify behavior (dùng đúng dependencies đúng cách); Spy khi muốn observe real implementation; Fake khi cần realistic behavior nhưng không thể/không muốn dùng real service.
- Overcrowded mocks là code smell: nếu test cần mock quá nhiều dependencies, code đang vi phạm Single Responsibility Principle — refactor code, không thêm mocks.
Mock verifies interactions (assertions), Stub provides canned responses, Spy observes real implementations, Fake has a simpler working implementation — overcrowded mocks are a code smell, usually signaling an SRP violation.
- Test doubles are replacements for real dependencies in tests — classified by Martin Fowler in 'Mocks Aren't Stubs'.
- Dummy: a placeholder object that is passed in but never actually used — for example, passing null or an empty object to fulfill a parameter requirement.
- Stub: returns pre-configured responses to calls — does not verify interactions, only provides canned answers; for example, a stub database that returns a fixed user object.
- Mock: pre-programmed with expectations about the calls it will receive — verifies that those interactions actually happen; jest.fn() is a mock because you can assert toHaveBeenCalledWith(); the test fails if expected calls do not occur.
- Spy: wraps the real implementation and records calls — jest.spyOn() calls the real method by default and records the arguments; can be overridden with mockImplementation when needed.
- Fake: has a simpler working implementation than the real one — a fake in-memory database (Map<id, entity>), a fake email service (stores emails in an array instead of sending them), a fake message queue.
- Practical guidance: use a Stub when you need to control return values; use a Mock when you want to verify behavior (dependencies are used correctly); use a Spy when you want to observe the real implementation; use a Fake when you need realistic behavior but cannot or do not want to use the real service.
- Overcrowded mocks are a code smell: if a test needs to mock too many dependencies, the code is likely violating the Single Responsibility Principle — refactor the code, do not add more mocks.