Spring Boot Junit 5 Mockito

By | | Updated : 2022-05-19 | Viewed : 148 times

Spring Boot Junit 5 Mockito

We will learn how to set up the Junit 5 and Mockito in a Spring boot application. We will focus on different unit test cases to test the controller, service, and DAO layers using Junit 5 and Mockito.

Set up Maven Dependencies

Maven Dependencies For Spring Boot, Junit 5 and Mockito
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-test</artifactId>
    <scope>test</scope>
    <exclusions>
        <exclusion>
            <groupId>org.junit.vintage</groupId>
            <artifactId>junit-vintage-engine</artifactId>
        </exclusion>
    </exclusions>
</dependency>

spring-boot-starter-test dependency will fetch all the required libraries as shown below. Here we want to use the Junit 5. So we are excluded the Junit Vintage library.

Maven Dependencies For Spring Boot, Junit 5 and Mockito

Here I am going to use a previous example Spring Boot Rest Api Crud Example to add test cases using Junit and Mockito libraries.

Spring Boot Rest Controller Unit Test Example

Spring provides two annotations to write the unit test cases that we used to test the controller layer. We can use @SpringBootTest and @WebMvcTest to write unit test cases. @WebMvcTest is especially for testing the controller layer.

@SpringBootTest vs @WebMvcTest

@SpringBootTest: Spring loads the full application context and injected all beans here. So we can test different classes without worrying about dependencies injection. The essential purpose of the @SpringBootTest is integration testing. As @SpringBootTest allows Spring to inject all beans, application test’s execution becomes slower.

@WebMvcTest: @WebMvcTest allows the Spring to load only Controllers and its dependencies. So we can use this to test the Controller layer and not possible for the remaining layer and beans. As @WebMvcTest allows Spring to load only the controller, the application’s test execution becomes faster.

We write the unit test cases for controller. Please see the below given examples.

SpringBootTest Controller Unit Test Example1
@ExtendWith(SpringExtension.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class SpringBootJunit5MockitoExampleAppTests1 {

	@LocalServerPort
	private int port;

	@Autowired
	private TestRestTemplate testRestTemplate;

	@Autowired
	ProductsController productsController;

	@Test
	public void contextLoads() {
	}

	@Test
	public void testWeb_WhenSuccessIsResult() throws Exception {
		assertThat(testRestTemplate.getForObject("http://localhost:" + port + "/curd-app/api/testWeb", String.class)).contains("Result: Success");
	}

}

We can pass the different types of parameters into @SpringBootTest. You can refer this to know more about @SpringBootTest. Here we passed the random port to webEnvironment.

@ExtendWith(SpringExtension.class): You might have observed the @ExtendWith(SpringExtension.class) annotation examples. Spring uses this annotation to create and initiate the mock objects into the Junit framework.

We can add and configure the @AutoConfigureMockMvc to the above example. Notice below example.

SpringBootTest Controller Unit Test Example2
@ExtendWith(SpringExtension.class)
@SpringBootTest
@AutoConfigureMockMvc
public class SpringBootJunit5MockitoExampleAppTests2 {

    @Autowired
    private MockMvc mockMvc;

    @Test
    public void testWeb_WhenSuccessIsResult() throws Exception {
        mockMvc.perform(get("/curd-app/api/testWeb")).andDo(print()).andExpect(status().isOk())
                .andExpect(content().string(containsString("Result: Success")));
    }
}

@SpringBootTest with @AutoConfigureMockMvc will restrict to load of the entire application context. It also allows to configure and use MockMVC class to test the controllers.

We will look into @WebMvcTest to write the controller layer. Please see the below example.

SpringBootTest Controller Unit Test Example3
@ExtendWith(SpringExtension.class)
@WebMvcTest(ProductsController.class)
public class SpringBootJunit5MockitoExampleAppTests3 {

    @Autowired
    private MockMvc mockMvc;

    @MockBean
    private ProductServiceImpl productServiceImpl;
    private List<Product> productList;
    private Product product;
    private String requestJson;

    @BeforeEach
    void setUp() throws JsonProcessingException {
			
		//set up the products and product
    }

    @Test
    public void testWeb_WhenSuccessIsResult() throws Exception {
        this.mockMvc.perform(get("/curd-app/api/testWeb")).andDo(print()).andExpect(status().isOk())
                .andExpect(content().string(containsString("Result: Success")));
    }

    @Test
    public void givenProducts_whenGetProducts_thenReturnJsonArray() throws Exception {
        given(productServiceImpl.getAllProducts()).willReturn(new ResponseEntity(productList, HttpStatus.OK));
        this.mockMvc.perform(get("/curd-app/api/products").contentType(MediaType.APPLICATION_JSON))
                .andExpect(status().isOk())
                .andExpect(content().string(containsString("productVendor2")));
    }

    @Test
    public void testSaveProduct_WhenProduct_NotNull() throws Exception {

        this.mockMvc.perform(
                post("/curd-app/api/products")
                        .contentType(MediaType.APPLICATION_JSON).content(requestJson))
                .andDo(print())
                .andExpect(status().isOk());
    }

}

You can find more unit test cases for different scenarios. Please observe the below above code.

Spring Boot Service Unit Test Example

We will write now the test cases for service to cover different scenarios here. Please see the below example for service layer unit tests.

Spring Boot Service Unit Test Example
@ExtendWith(MockitoExtension.class)
public class ProductServiceImplTest {

    @InjectMocks
    ProductServiceImpl productServiceImpl;
    @Mock
    ProductRepository productRepository;

    List productsExpected;
    Product productExpected;

    @BeforeEach
    public void setUp() throws IOException {
        productsExpected = TestUtils.getProducts();
        productExpected = (Product) productsExpected.get(0);
    }


    @Test
    public void getAllProductsTest() throws IOException {

        when(productRepository.findAll()).thenReturn(productsExpected);
        ResponseEntity responseEntityExpected  = productServiceImpl.getAllProducts();
        Object objectReal = responseEntityExpected.getBody();
        Product productReal = null;
        if(objectReal instanceof List){
            List productsReal = (List)objectReal;
            productReal = (Product) productsReal.get(0);
        }
        assertNotNull(productReal);
        assert(productReal.getProductVendorName().equals(productExpected.getProductVendorName()));

    }
}

@ExtendWith(MockitoExtension.class): In earlier versions of Junit, Mockito JUnit Runner creates the mocks for classes which are annotated with @Mock. Mockit Junit Runner handles the stubbing part also. MockitoExtension work same as Mockit Junit Runner does. The registration of MockitoExtension will be occurred using with @ExtendWith annotation.

@Mock: Mockito provides @Mock annotation to create the mock objects.

@InjectMocks: Mockito provide @InjectMocks annotattion to inject all the mocks into tested class object.

Spring Boot Repository Unit Test Example

We will write and test now the repository using @DataJpaTest and @AutoConfigureTestDatabase. Please look at the given code example below for the repository in which contains same annotations.

Spring Boot Repository Unit Test Example
@ExtendWith(SpringExtension.class)
@DataJpaTest
@AutoConfigureTestDatabase(replace= AutoConfigureTestDatabase.Replace.NONE)
public class ProductRepositoryTest {

    @Autowired
    ProductRepository productRepository;

    @Test
    void saveProduct_success(){
        Product product = new Product();
        product.setProductId(101l);
        product.setProductName("testName");
        product.setProductVendorName("testVendorName");
        Product productResult = productRepository.save(product);
        assertThat(productResult).isNotNull();
    }

    @Test
    void saveAll_success() {
        List<Product> products = Arrays.asList(
                new Product(1001L,"product1", "vendor1"),
                new Product(1002L,"product2", "vendor2"),
                new Product(1003L,"product3", "vendor3")
        );
        Iterable<Product> allProducts = productRepository.saveAll(products);
        assertThat(allProducts).hasSize(3);
    }

    @Test
    public void findAll_success() {
        Iterable<Product> products = productRepository.findAll();
        assertThat(products).isNotEmpty();
    }
    @Test
    public void deleteAll_success() {
        productRepository.deleteAll();
        assertThat(productRepository.findAll()).isEmpty();
    }
}

@DataJpaTest is mainly designed to write unit tests and for testing JPA components and should be used with the combination of @ExtendWith(SpringExtension.class). Tests annotated with @DataJpaTest in spring are transactional and roll back after completion of each test. Test annotated with @DataJpaTest can use an in-memory database. @AutoConfigureTestDatabase is used to override the settings of @DataJpaTest.

Please find the GitHub repo for this tutorial here Spring-Boot-Junit5-Mockito-Example-App

Leave A Reply