목, 스텁, 페이크
테스트 대역인 목, 스텁, 페이크, 더미를 구분하고 테스트에서 각각 어떤 역할을 하는지 이해합니다.
목, 스텁, 페이크은(는) CoddyKit의 무료 Testing Mastery: JUnit, Mockito & Integration Tests 강의입니다. 이것은 4개 중 1번째 강의입니다. 아래에서 전체 강의를 무료로 읽을 수 있으며, 내장 코드 에디터와 24/7 AI 튜터와 함께 브라우저에서 직접 실습할 수 있습니다. 이 강의는 Testing Mastery: JUnit, Mockito & Integration Tests 학습 경로의 일부이며, 진행 상황이 웹과 CoddyKit 앱에 동기화됩니다. Testing Mastery: JUnit, Mockito & Integration Tests 강의에는 총 4개의 강의가 포함되어 있습니다.
이 강의의 일부는 아직 번역되지 않았으며 영어로 표시됩니다.
What are Test Doubles?
When testing a class, it often depends on other classes. These "dependencies" can make tests tricky! Test doubles are stand-in objects that mimic the behavior of real dependencies.
They help isolate the code you're testing, making your tests faster, more reliable, and easier to write.
Why Do We Need Them?
Imagine testing a class that sends emails or talks to a database. You don't want your tests to:
- Actually send emails (spam!).
- Slow down by hitting a real database.
- Depend on external services that might be unavailable.
Test doubles solve these problems by providing controlled, predictable replacements.
Dummy Objects: Just Placeholders
A Dummy Object is the simplest kind of test double. It's passed around but never actually used.
Think of it as a required parameter that your code doesn't care about in a specific test scenario. It just fills a slot.
- Often
nullor an empty instance. - No behavior is expected from it.
- Used when an argument is needed but irrelevant for the test.
Dummy Example: Irrelevant Data
Consider a UserService that needs an EmailSender but in a test scenario, we only care about user creation, not email sending.
Here, a null or a basic new EmailSender() might act as a dummy.
interface EmailSender {
void sendEmail(String to, String subject, String body);
}
class UserService {
private EmailSender emailSender;
public UserService(EmailSender emailSender) {
this.emailSender = emailSender;
}
public boolean createUser(String username) {
// In this specific test, we don't care about emailSender
// emailSender.sendEmail(username + "@example.com", "Welcome", "Hi!");
return true; // Simplified for example
}
}
public class Main {
public static void main(String[] args) {
// Here, null acts as a dummy object for createUser test
EmailSender dummySender = null;
UserService userService = new UserService(dummySender);
boolean created = userService.createUser("testuser");
System.out.println("User created: " + created);
}
}Stub Objects: Canned Responses
A Stub Object provides pre-programmed answers to method calls during a test. It doesn't perform any real logic; it just returns specific values.
Stubs are great when your test needs a dependency to return a particular piece of data to proceed.
- Returns fixed, predetermined values.
- Focuses on state-based testing.
- Doesn't verify interactions, just supplies data.
Stub Example: Fixed Data
Let's say a ProductService needs a ProductRepository to find products. A stub can return a specific product without hitting a real database.
interface ProductRepository {
String findProductNameById(int id);
}
class ProductRepositoryStub implements ProductRepository {
@Override
public String findProductNameById(int id) {
if (id == 1) {
return "Laptop";
}
return "Unknown Product";
}
}
class ProductService {
private ProductRepository repository;
public ProductService(ProductRepository repository) {
this.repository = repository;
}
public String getProductDetails(int productId) {
return "Product: " + repository.findProductNameById(productId);
}
}
public class Main {
public static void main(String[] args) {
ProductRepository stub = new ProductRepositoryStub();
ProductService service = new ProductService(stub);
System.out.println(service.getProductDetails(1));
System.out.println(service.getProductDetails(2));
}
}Fake Objects: Light Implementations
A Fake Object has a working implementation, but it's simplified compared to the real one. It typically takes shortcuts that make it unsuitable for production but perfect for tests.
An in-memory database or a file system replacement are common examples of fakes.
- Contains some logic, not just canned responses.
- Simulates real behavior, but in a simpler way.
- Useful for integration-like unit tests.
Fake Example: In-Memory DB
Here's a fake UserRepository that stores users in a simple HashMap instead of a real database. It simulates adding and finding users.
import java.util.HashMap;
import java.util.Map;
interface UserRepository {
void addUser(String name);
String findUser(String name);
}
class InMemoryUserRepository implements UserRepository {
private Map<String, String> users = new HashMap<>();
@Override
public void addUser(String name) {
users.put(name, name);
}
@Override
public String findUser(String name) {
return users.get(name);
}
}
class UserService {
private UserRepository repository;
public UserService(UserRepository repository) {
this.repository = repository;
}
public void registerUser(String username) {
repository.addUser(username);
}
public boolean userExists(String username) {
return repository.findUser(username) != null;
}
}
public class Main {
public static void main(String[] args) {
UserRepository fakeRepo = new InMemoryUserRepository();
UserService service = new UserService(fakeRepo);
service.registerUser("Alice");
System.out.println("Alice exists: " + service.userExists("Alice"));
System.out.println("Bob exists: " + service.userExists("Bob"));
}
}Mock Objects: Behavior Verification
A Mock Object is a special type of stub that also records interactions. You use mocks to verify that a specific method was called on a dependency, with specific arguments, and a certain number of times.
Mocks are central to behavior-driven testing, where you care about how your object interacts with its collaborators.
- Records method calls and arguments.
- Allows verification of interactions.
- Often created by mocking frameworks (like Mockito!).
Mocks vs. Stubs: Behavior or State?
The main difference lies in their purpose:
- Stubs: Focus on state verification. They provide data needed for the test to run, and the test asserts on the state of the system under test.
- Mocks: Focus on behavior verification. They verify that the system under test interacted with its dependencies in a specific way.
You often combine them: a stub provides data, and a mock verifies an action.
Test Double Check
Which type of test double is primarily used to verify that a specific method was called on a dependency?
Recap: The Test Double Family
We've explored the different types of test doubles and why they're essential for writing good tests:
- Dummy: A placeholder, passed but not used.
- Stub: Provides canned answers to method calls.
- Fake: A simplified working implementation.
- Mock: Verifies interactions and behavior.
Understanding these helps you choose the right tool for isolating and testing your code effectively. Next, we'll dive into how Mockito helps us create these mocks!
자주 묻는 질문
“목, 스텁, 페이크” 강의는 무료인가요?
네 — “목, 스텁, 페이크” 전체 내용을 이 웹사이트에서 무료로 읽을 수 있습니다. 인터랙티브하게 실습하려면(내장 코드 에디터와 24/7 AI 튜터), CoddyKit PRO로 업그레이드하면 Testing Mastery: JUnit, Mockito & Integration Tests 강의 전체를 잠금 해제할 수 있습니다. Testing Mastery: JUnit, Mockito & Integration Tests 강의에는 총 4개의 강의가 포함되어 있습니다.
“목, 스텁, 페이크”에서 뭘 배우나요?
테스트 대역인 목, 스텁, 페이크, 더미를 구분하고 테스트에서 각각 어떤 역할을 하는지 이해합니다. 브라우저에서 직접 실행하는 실습 코드로 Testing Mastery: JUnit, Mockito & Integration Tests을(를) 배우며, 24/7 AI 튜터가 강의를 진행하면서 질문에 답변해줍니다.
Testing Mastery: JUnit, Mockito & Integration Tests을(를) 시작하는 데 경험이 필요한가요?
사전 경험은 필요하지 않습니다. CoddyKit의 Testing Mastery: JUnit, Mockito & Integration Tests은(는) 초급자부터 고급 학습자까지를 위해 구성되어 있으므로, 여기서 시작하거나 처음부터 시작할 수 있으며 자신의 속도대로 진행할 수 있습니다. 이것은 4개 중 1번째 강의입니다.
“목, 스텁, 페이크” 강의는 얼마나 걸리나요?
대부분의 CoddyKit 강의는 약 5~10분이 소요됩니다. 각 강의는 간결하고 인터랙티브하여 꾸준한 진행이 가능하며, 웹과 앱에서 중단한 부분부터 바로 시작할 수 있습니다.
이 Testing Mastery: JUnit, Mockito & Integration Tests 강의에서 코드를 작성하고 실행할 수 있나요?
네. 모든 Testing Mastery: JUnit, Mockito & Integration Tests 강의에는 내장 코드 에디터가 포함되어 있으므로, 브라우저에서 바로 실제 코드를 작성하고 실행한 후 즉시 AI 피드백을 받을 수 있습니다 — 로컬 설정이 필요 없습니다.