Test Double Types | Java Fresher Interview
Fast recall
Quick revision
Core answer
spy(realObject) means a partial mock that calls the real object by default; that is narrower than some classic uses of the word test spy.Interview-ready guide
Interview answer
A test double is any object used instead of a real collaborator during a test. A dummy only fills a parameter. A stub returns prepared data. A fake has a small working implementation, such as a Map-backed repository. A test spy records information for later checks, while a mock is used to verify expected interactions. These are roles, so one object can play more than one. A Mockito mock, for example, can both return stubbed values and record calls for verify. Mockito also uses the term spy for spy(realObject), a partial mock where unstubbed methods call the real object. I keep that library meaning separate from the broader vocabulary.
Test Double Types | Java Fresher Interview
Direct Answer
A test double is any object used in place of a collaborator during a test. Common roles are dummy, stub, fake, spy, and mock. The words describe how the double is used: a stub supplies answers, a fake has simplified working behavior, and a mock verifies expected interactions. In Mockito specifically, spy(realObject) means a partial mock that calls the real object by default; that is narrower than some classic uses of the word test spy.
Code Example
@ExtendWith(MockitoExtension.class)
class TestDoubleExamplesTest {
@Test
void dummyExample() {
// Dummy: passed but never called—just satisfies parameter requirement
var logger = mock(Logger.class);
var service = new OrderService(mock(OrderRepository.class), logger);
// logger methods are never invoked in this test
}
@Test
void stubExample() {
var repo = mock(OrderRepository.class);
// Stub: returns canned data when called
when(repo.findById(1L)).thenReturn(Optional.of(new Order(1L, "Book")));
var order = repo.findById(1L).get();
assertEquals("Book", order.item());
}
@Test
void fakeExample() {
// Fake: simplified working implementation using in-memory storage
var fakeRepo = new InMemoryOrderRepository();
fakeRepo.save(new Order(1L, "Laptop"));
assertEquals(1, fakeRepo.count()); // real logic, no database
}
@Test
void mockExample() {
var emailService = mock(EmailService.class);
var orderService = new OrderService(mock(OrderRepository.class), emailService);
orderService.placeOrder(new Order(1L, "Phone"));
// Mock: verify interaction happened with correct arguments
verify(emailService).sendConfirmation("Phone");
}
@Test
void spyExample() {
var realValidator = spy(new EmailValidator());
// Spy: real methods run except where stubbed
doReturn(true).when(realValidator).checkDomain(anyString());
assertTrue(realValidator.isValid("test@example.com")); // real validation + stubbed domain check
}
}
Common Mistakes & Pitfalls
- Calling everything a mock: Freshers say "I'm mocking the repository" when they're actually stubbing it with when().thenReturn(). A true mock uses verify() to assert interactions. Imprecise language suggests unclear thinking about what the test validates.
- Overusing verify(): Writing verify() on every mock turns unit tests into fragile change detectors. Only verify interactions that matter to the test's purpose—if you're testing order totals, verifying that logger.info was called is noise.
- Not knowing when to use Fakes: Freshers mock everything when a simple Fake (like an in-memory list) would make tests clearer. If your test setup has ten when() statements recreating a repository's behavior, you need a Fake implementation instead.
Check your understanding
Answer these without looking back at the article.
- What is an in-memory database and when do you use it in tests?
- What is MockMvc in Spring?
- When would you choose a Fake over a Mock?
Looking for a structured roadmap?
Every module on this page is also part of the full Java backend interview track.