In this post, we’ll cover the basics of mocking objects when unit testing Spring Boot applications with examples.
Check out all the other parts of our blog post series on Spring Boot:
- Part 1: An introduction to Spring Boot: the basics
- Part 2: Spring Boot testing best practices & guide
- Part 3: Spring framework basics: Spring vs Spring Boot vs Spring Web MVC vs Spring WebFlux
- Part 4: Spring Web MVC vs Spring WebFlux: differences between Spring web frameworks
- Part 6: What is the difference between @Controller vs @RestController in Spring Boot?
- Part 7: Spring Boot folder structure best practices
Table of contents:
- What is mocking?
- Mocking in Spring Boot with Mockito & JUnit
- Comparing the
@MockBean
vs@Mock
annotations in Spring Boot: which one to use? - +1: Mocking for Spring MVC web applications
- Generating tests with mocks using Symflower
What is mocking?
In the context of unit testing, mocking is used to replace the external dependencies with “mocked” objects that simulate the behavior of real objects. The advantage of mocking is that it lets you test isolated “units” (e.g. components) of your application. Mocking lets you rule out any dependencies interfering with how the tested unit works, since mocked objects will always work the way you configured them. Mocking also lets you test independently of the status of those external dependencies, e.g. other components that are still being developed.
🤔 Wondering which mocking framework to use?
Check out our post: Mocking frameworks for Java: Mockito vs EasyMock vs JMockit
Mocking in Spring Boot with Mockito & JUnit
Mocking in Spring Boot is usually done with a combination of Mockito and JUnit, so that’s what we’ll cover in the following sections.
When unit testing Spring Boot applications, there are three options* to create mocks. It’s important to know the differences since you have to use each one of them differently.
*)Well actually, there are four. 💡 You could just use Symflower to generate smart test templates and entire unit test suites. Symflower supports mocking out of the box. See an example at the bottom of this post, and let us know if you need help generating tests with mocks.
Three ways to create mocks in Spring Boot: @MockBean
, @Mock
, or Mockito.mock()
Using the @MockBean
annotation in Spring Boot
The most straightforward option is just to use @MockBean
, the most simple way to mock an object in Spring Boot.
@MockBean
is a Spring Boot annotation that is provided by the Spring Boot Test module. Use @MockBean
to define mocks for beans inside your ApplicationContext
, including beans auto-configured by Spring Boot, and beans that you have declared in your application’s configuration file.
@MockBean
lets you add new beans: if a bean definition with the same type already exists in the application context, it will simply be replaced with a mock. A great thing about @MockBean
is that you can use it on test classes, fields within your test, or @Configuration
classes or fields.
Note that mocked beans will be automatically reset after each test method and that when you use @MockBean
on a field, Spring Boot will automatically take care of injecting the instance of the created mock.
Example: using @MockBean
:
@SpringBootTest
public class UserServiceIntegrationTest {
@Autowired
private UserService userService;
@MockBean
private UserRepository userRepository;
@Test
public void testGetUserById() {
// Given
User mockedUser = new User("John", "Doe", 25);
when(userRepository.findById(1L)).thenReturn(Optional.of(mockedUser));
// When
User result = userService.getUserById(1L);
// Then
assertNotNull(result);
assertEquals("John", result.getFirstName());
assertEquals("Doe", result.getLastName());
assertEquals(25, result.getAge());
verify(userRepository).findById(1L); // Verify that the findById method was called
}
}
Source: java67.com
Using the @Mock
annotation in Spring Boot
There’s some chance you’re already familiar with @Mock
as it is also used in plain Java (e.g. non-Spring) applications. @Mock
is actually a shorthand for Mockito.mock()
(see below), so it’s recommended that you use it for cleaner code.
This annotation is provided by the Mockito library and is useful when you’re using dependencies that are not part of your application’s Spring context. @Mock
lets you mock these objects using Mockito very simply.
Note that you can only use @Mock
within test classes. It’s a good idea to use it if you want to reuse the mocked object and avoid calling the mock() method several times. @Mock
lets you specify a name for the mocked object which improves code readability and facilitates finding errors. Another neat feature of @Mock
is that it also allows you to use @InjectMocks
to inject a mock object into another mock object.
To use @Mock
, you’ll need to enable the use of Mockito annotations either by using MockitoJUnitRunner
or by calling the MockitoAnnotations.initMocks()
method. To initialize mock objects, use the MockitoJUnitRunner
or the MockitoExtension
classes.
- Note that
MockitoJUnitRunner
is JUnit 4-specific, and is used in a class-level annotation:@RunWith(MockitoJUnitRunner.class)
! MockitoExtension
, on the other hand, is the JUnit 5-specific version that is also used in a class-level annotation:@ExtendWith(MockitoExtension.class)
.
Example: using @Mock
:
import static org.mockito.Mockito.*;
@RunWith(MockitoJUnitRunner.class)
public class UserServiceTest {
@Mock
private UserRepository userRepository;
@InjectMocks
private UserService userService;
@Test
public void testGetUserById() {
// Given
User mockedUser = new User("John", "Doe", 25);
when(userRepository.findById(1L)).thenReturn(Optional.of(mockedUser));
// When
User result = userService.getUserById(1L);
// Then
assertNotNull(result);
assertEquals("John", result.getFirstName());
assertEquals("Doe", result.getLastName());
assertEquals(25, result.getAge());
verify(userRepository).findById(1L); // Verify that the findById method was called
}
}
Source: java67.com
Using Mockito.mock()
in Spring Boot
An easy one here: Mockito.mock()
is actually the same thing as @Mock
. Like @Mock
, you can use it to create a mock object of classes and interfaces, and it lets you create mock class fields and local mocks in methods.
However, @Mock
is considered a cleaner solution and is generally recommended over Mockito.mock()
. Other advantages of using @Mock
over Mockito.mock()
are that you can inject mocks created with @Mock
into the class you’re testing using @InjectMocks
. Also, if there is an error with your mock, the name of the mock annotated with @Mock
will be shown in the error messages so it’s easier to identify the problem. For those reasons (and for easily readable code), we recommend using @Mock
over Mockito.mock()
.
In case you do need to use it, here’s an example of how to do it!
Example: Mockito.mock()
:
// Example interface
public interface GreetingService {
String greet(String name);
}
// Test case using Mockito.mock()
@Test
public void testGreet() {
// Create a mock object of MyService
GreetingService myServiceMock = Mockito.mock(GeetingService.class);
// Define behavior for the greet() method
Mockito.when(myServiceMock.greet(Mockito.anyString())).thenReturn("Hello, ");
// Test the method that depends on MyService
MyClass myClass = new MyClass(myServiceMock);
String result = myClass.greet("John");
// Verify the expected behavior
Mockito.verify(myServiceMock).greet("John");
Assert.assertEquals("Hello, John", result);
}
Source: java67.com
Comparing the @MockBean
vs @Mock
annotations in Spring Boot: which one to use?
So which method should you use for mocking in Spring Boot? Here are a few things to bear in mind:
- Use
@Mock
for plain JUnit tests with Mockito.@Mock
is not aware of your Spring context, and you should rely on it when testing isolated components of your application. @MockBean
is aware of the application context and is therefore used for Spring Boot tests to mock dependencies in a Spring application context, including beans annotated with @Service, @Repository, or @Component.- Remember the different imports:
@Mock
should be imported from theorg.mockito
package, while@MockBean
resides in theorg.springframework.boot.test.mock.mockito
package. - You’ll need to manually inject mock objects annotated with
@Mock
to the test instance. You can do this using@InjectMocks
or by callingMockitoAnnotations.initMocks(...)
in your test setup.@MockBean
takes care of that automatically by replacing the actual bean with the mock in your Spring context.
+1: Mocking for Spring MVC web applications
When working on Spring MVC web applications, the Spring MVC Test framework (MockMVC) can be used to manage request handling with mock request and response objects.
😳 Spring Web MVC or Spring WebFlux?
So if you are developing RESTful applications, it is worth taking a look at the capabilities that MockMvc
provides. To sum it all up, you can test all HTTP requests such as PUT/GET/POST
requests including support for URI and request parameters.
For our example, let’s assume we have a BookController
class that offers a GET
mapping on the URI /books/most-popular
. In this case, the test using MockMvc
might look as follows:
@RunWith(SpringRunner.class)
@WebMvcTest(BookController.class)
public class BookControllerTest {
@Autowired
private MockMvc mockMvc;
...
@Test
public void getMostPopularBookByISBN() throws Exception {
this.mockMvc.perform(get("/books/most-popular"))
.andExpect(status().isOk())
.andExpect(view().name(""))
.andExpect(content().string(""));
}
}
Generating tests with mocks using Symflower
While it’s not rocket science, it can certainly take a bit of time to write the above code for every class being tested. Instead of manually typing code, we used Symflower to generate the test code above (e.g. the test for the BookController
class). All it took was a single click in our editor.
Symflower is integrated into your IDE so it can generate test templates with mocks right where you do your coding without disrupting your workflow:
Try Symflower in your editor, or get in touch with us to discuss generating tests for your project.
Make sure you never miss any of our upcoming content by signing up for our newsletter and by following us on X, LinkedIn, and Facebook.