You will use @MockBean annotation to create and automatically add mocks to Spring ApplicationContext. In this tutorial, we will look at different ways you can use @MockBean annotation to create mocks.
If you are testing your application with JUnit and Mockito, then there are many other useful tutorials you will find on the Testing Java Code page.
@MockBean Annotation at Field Level
One of the most common ways developers use @MockBean annotation is at the field level.
@MockBean private UsersServiceImpl usersService;
Below is a longer code example with a test method.
@WebMvcTest(controllers=UsersController.class, excludeAutoConfiguration = { SecurityAutoConfiguration.class }) class UsersControllerWebLayerIntegrationTest { @Autowired private MockMvc mockMvc; @MockBean private UsersServiceImpl usersService; private UserDetailsRequestModel userDetailsRequestModel; @Test @DisplayName("User can be created") void testCreateUser_whenValidDetailsProvided_returnsUserDetails() throws Exception { // Arrange UserDto userDto = new UserDto(); userDto.setFirstName("Sergey"); userDto.setLastName("Kargopolov"); userDto.setEmail("[email protected]"); UserDto userDto = new ModelMapper().map(userDetailsRequestModel, UserDto.class); userDto.setUserId(UUID.randomUUID().toString()); when(usersService.createUser(any(UserDto.class))).thenReturn(userDto); RequestBuilder requestBuilder = MockMvcRequestBuilders.post("/users") .content(new ObjectMapper().writeValueAsString(userDetailsRequestModel)) .contentType(MediaType.APPLICATION_JSON) .accept(MediaType.APPLICATION_JSON); // Act MvcResult result = mockMvc.perform(requestBuilder).andReturn(); String responseBodyAsString = result.getResponse().getContentAsString(); UserRest createdUser = new ObjectMapper().readValue(responseBodyAsString, UserRest.class); // Assert Assertions.assertEquals(userDetailsRequestModel.getFirstName(), createdUser.getFirstName(), "Returned user's first name is most likely incorrect"); Assertions.assertEquals(userDetailsRequestModel.getLastName(), createdUser.getLastName(), "Returned user's last name is most likely incorrect"); Assertions.assertEquals(userDetailsRequestModel.getEmail(), createdUser.getEmail(), "Returned user's email is most likely incorrect"); Assertions.assertFalse(createdUser.getUserId().isEmpty(),"userId should not be empty"); } }
Note: You can use @MockBean annotation to register mocks by type or by bean name.
- When you register mock by type, then any existing single bean of a matching type (including subclasses) in ApplicationContext will be replaced by the mock.
- On the other hand, when you register mock by name, then an existing bean with the same name will be replaced with a mock object,
Multiple Beans of the Same Type
It is possible that your application will have beans that implement the same interface. In this case, you will use @Qualifier(“beanName”) annotation to specify which bean you want to replace with a mock object.
@WebMvcTest(controllers=UsersController.class) class UsersControllerWebLayerIntegrationTest { @Autowired private MockMvc mockMvc; @MockBean @Qualifier("usersService") private UsersServiceImpl usersService; ... }
@MockBean Annotation at Class Level
You can also use @MockBean annotation at the Class level. In this case, you will need to do two things:
- Annotate the class with @MockBean annotation and specify the data type of the implementation class,
- User @Autowired annotation to inject the created mock into the member variable.
@WebMvcTest(controllers=UsersController.class) @MockBean(UsersServiceImpl.class) class UsersControllerWebLayerIntegrationTest { @Autowired private MockMvc mockMvc; @Autowired private UsersService usersService; ... }
@MockBean Annotation Outside of Test Class
You can also move mock definitions outside of test class. In this case, you will do the following:
- Create a new class and annotate it with @Configuration annotation,
- Create mock object using @MockBean annotation,
- Inject mock object into a Test class.
Step 1. Create a mock object in a separate @Configuration class
@Configuration @MockBean(UsersServiceImpl.class) public class MockBeansConfiguration { }
Step 2. Inject mock object into a Test class
@WebMvcTest(controllers=UsersController.class) @MockBean(UsersServiceImpl.class) class UsersControllerWebLayerIntegrationTest { @Autowired private MockMvc mockMvc; @Autowired private UsersService usersService; ... }
@MockBean vs @Mock
The main difference between @MockBean and @Mock annotations is that @MockBean annotation will automatically place a mock object into Spring ApplicationContext. If your application does not use Spring Framework and you do not need the mock object to be placed into Spring ApplicationContext, then you will use a regular Mockito’s @Mock annotation.
However, if needed, you can also use @Mock annotation to place the mock object into Spring ApplicationContext. Below is an example of how you can do it.
Step 1. Create a mock object as a @Bean
@Configuration public class MockBeansConfiguration { @Bean public UsersService getUsersService() { return Mockito.mock(UsersServiceImpl.class); } }
Step 2. Inject mock object into a Test class
@WebMvcTest(controllers=UsersController.class) @MockBean(UsersServiceImpl.class) class UsersControllerWebLayerIntegrationTest { @Autowired private MockMvc mockMvc; @Autowired private UsersService usersService; ... }
Video Lessons
I hope this tutorial was helpful to you. If you like learning by watching a series of step-by-step video lessons, then have a look at my video course called “Testing Java with JUnit and Mockito“. This video course is for absolute beginners, and you do not need to have any prior knowledge of testing Java applications to enrol.
Otherwise, visit the Testing Java Code page and explore our extensive collection of Mockito tutorials. From basic concepts to advanced techniques, these resources will equip you with the knowledge to conduct thorough and efficient tests in your Java projects.
Happy learning!