Skip to content
thesarfo

Concept

Spring: Unit Testing Services with Mockito

Why testing a service means mocking its repository dependency, using @MockBean in a Spring context and plain Mockito with @ExtendWith(MockitoExtension.class).

views 0

Say we have a service:

@Service
public class ProductService {
private final ProductRepository productRepository;
public ProductService(ProductRepository productRepository) {
this.productRepository = productRepository;
}
public List<String> getProductNamesWithEvenNoOfChar() {
List<String> names = productRepository.getProductNames();
List<String> result = new ArrayList<>();
for (String n : names) {
if (n.length() % 2 != 0) {
result.add(n);
}
}
return result;
}
}

And a repository:

@Repository
public class ProductRepository {
public List<String> getProductNames() {
return Arrays.asList("aaa", "bb", "cacc", "aca");
}
}

We can test it by calling the method under test and using assert to check the result:

@SpringBootTest
class TestingApplicationTests {
@Autowired
private ProductService productService;
@Test
void noProductsReturnedTest() {
List<String> res = productService.getProductNamesWithEvenNoOfChar();
assertTrue(res.isEmpty()); // assert is used for checking results of tests
}
}

This test fails, because getProductNamesWithEvenNoOfChar() actually returns products with an odd number of characters — but it does so by calling the repository, whose real implementation returns a fixed list. Testing the service ends up depending on the repository’s real behavior. This is the typical case for mocking the repository, using Mockito’s @MockBean.

Mocking creates a fake object standing in for a dependency, which you can control. Here, a fake ProductRepository that returns whatever list we want:

@MockBean
private ProductRepository productRepository;
@Autowired
private ProductService productService;
@Test
void noProductsReturnedTest() {
given(productRepository.getProductNames())
.willReturn(Collections.emptyList());
List<String> res = productService.getProductNamesWithEvenNoOfChar();
assertTrue(res.isEmpty());
}

We tell the mock what to return when called (given(...).willReturn(...)), call the method under test, then assert on the result — a test is assumptions, a method call, then expectations.

We can also test that the method returns something real:

@Test
public void moreProductsAreFoundTest() {
List<String> input = Arrays.asList("aa", "bbbb", "ccc"); // input list
given(productRepository.getProductNames()).willReturn(input);
List<String> res = productService.getProductNamesWithEvenNoOfChar();
assertEquals(2, res.size());
}

When unit testing a class (like a service) that depends on other classes (like repositories), you typically mock the dependencies and inject them into the class under test — isolating it and controlling its dependencies’ behavior. Here’s the same idea with plain Mockito instead of a full Spring context:

import org.junit.jupiter.api.Test;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import static org.mockito.Mockito.*;
import org.mockito.junit.jupiter.MockitoExtension;
import org.junit.jupiter.api.extension.ExtendWith;
import java.util.Arrays;
import java.util.List;
@ExtendWith(MockitoExtension.class)
public class ProductServiceUnitTest {
@Mock
private ProductRepository productRepository;
@InjectMocks
private ProductService productService;
@Test
public void getProductNamesWithEvenNoOfCharTest() {
when(productRepository.getProductNames()).thenReturn(Arrays.asList("aa", "bbb", "cccc", "ddddd"));
List<String> res = productService.getProductNamesWithEvenNoOfChar();
assertEquals(2, res.size());
assertTrue(res.containsAll(Arrays.asList("aa", "cccc")));
}
}

When testing a controller, the same pattern applies: @Mock the services and other injected classes, and @InjectMocks on the controller class itself.