16.3 Service-Layer Slice Testing with Mockito
Mockito lets you cut dependencies between layers in unit tests — no real DB or external API connections required.
1. @Mock and @InjectMocks
@ExtendWith(MockitoExtension.class)
class ProductServiceTest {
@Mock
private ProductRepository productRepository;
@Mock
private CacheManager cacheManager;
@InjectMocks
private ProductService productService;
@Test
@DisplayName("When no cache hit, product is fetched from DB.")
void fetch_product_from_db() {
// Given
Long productId = 1L;
Product mockProduct = new Product(productId, "Spring Book", 35000);
given(productRepository.findById(productId)).willReturn(Optional.of(mockProduct));
// When
ProductDto result = productService.getProduct(productId);
// Then
assertThat(result.getName()).isEqualTo("Spring Book");
then(productRepository).should(times(1)).findById(productId);
}
@Test
@DisplayName("Fetching a non-existent product throws an exception.")
void non_existent_product_throws() {
given(productRepository.findById(anyLong())).willReturn(Optional.empty());
assertThatThrownBy(() -> productService.getProduct(999L))
.isInstanceOf(ProductNotFoundException.class);
}
}
2. ArgumentCaptor — Capturing Method Arguments
Verify exactly what arguments a mocked method was called with.
@Test
@DisplayName("Order creation passes correct data to the event publisher.")
void order_creation_event_verification() {
ArgumentCaptor<OrderCreatedEvent> captor = ArgumentCaptor.forClass(OrderCreatedEvent.class);
orderService.createOrder(new CreateOrderRequest(userId, productId, quantity));
then(eventPublisher).should().publishEvent(captor.capture());
assertThat(captor.getValue().getUserId()).isEqualTo(userId);
assertThat(captor.getValue().getQuantity()).isEqualTo(quantity);
}