thenAnswer() in Mockito
Fast recall
Quick revision
Core answer
Interview-ready guide
Interview answer
When you stub a method with then-return, you're giving it a fixed value that's returned no matter what arguments are passed.
But sometimes you need the return value to depend on the actual input. That's exactly what then-answer does. It takes a lambda that receives an invocation object, and you compute the return value inside that lambda based on the arguments.
The most common pattern is repository save methods. In real life, when you save an entity, the database generates an ID and returns the entity with that ID. So in your test, you'd use then-answer with a lambda that grabs the input entity using inv-dot-get-argument-zero, then returns a new entity with the same data but with a generated ID added.
Another common case is transformer methods, like a service that converts strings to uppercase. You'd use then-answer with inv-dot-get-argument-zero-comma-String-dot-class-dot-to-upper-case. One mistake freshers make is using then-answer when they don't actually need it.
If your return value doesn't depend on the input at all, just use then-return. It's simpler and makes the test clearer. But whenever you see your stubbed method should behave differently based on what's passed in, that's your signal to reach for then-answer.
thenAnswer() in Mockito
Direct Answer
thenAnswer lets you compute a return value dynamically based on the actual arguments passed to the stubbed method. Use it when the response depends on input, like returning a saved entity with a generated ID or transforming the input argument.
Code Example
@ExtendWith(MockitoExtension.class)
class OrderServiceTest {
@Mock
private OrderRepository orderRepository;
@InjectMocks
private OrderService orderService;
@Test
void testCreateOrder() {
// Simulate repository saving with generated ID
when(orderRepository.save(any(Order.class)))
.thenAnswer(inv -> {
Order input = inv.getArgument(0, Order.class);
return new Order(999L, input.item(), input.quantity()); // Add ID
});
var created = orderService.createOrder("Laptop", 2);
assertThat(created.id()).isEqualTo(999L);
assertThat(created.item()).isEqualTo("Laptop");
}
@Test
void testTransformInput() {
when(orderRepository.findByItemName(anyString()))
.thenAnswer(inv -> {
String itemName = inv.getArgument(0, String.class);
return Optional.of(new Order(1L, itemName.toUpperCase(), 1));
});
var found = orderService.findByItemName("laptop");
assertThat(found.item()).isEqualTo("LAPTOP"); // Transformed
}
}
Common Mistakes & Pitfalls
- Overusing thenAnswer for static values: Freshers sometimes use thenAnswer when a simple thenReturn would work, like when the return value doesn't depend on arguments at all. This makes tests harder to read. If you're not accessing inv.getArgument, you probably don't need thenAnswer.
- Wrong argument index: Getting arguments by the wrong index (forgetting zero-based indexing) causes ClassCastException at runtime. If your method is save(Long id, Order order) and you want the Order, it's index 1, not 0.
- Ignoring type safety: Using inv.getArgument(0) without the type parameter returns Object, forcing you to cast manually. Always use inv.getArgument(0, YourType.class) for type safety and cleaner code.
Check your understanding
Answer these without looking back at the article.
- How does thenAnswer() differ from doAnswer()?
- Can you chain thenAnswer() with thenReturn() for multiple successive calls?
Looking for a structured roadmap?
Every module on this page is also part of the full Java backend interview track.