Issue
I have built a REST API that does basic CRUD operations on a product database and I am now unit testing all the methods within the controller and service layer. I have realised that methods such as addProduct, updateProduct or deleteProduct return void on both of the layers.
How do I go about mocking the repository when testing the service layer and mocking the service while testing controller layer for these methods?
Controller method:
@RequestMapping(method= RequestMethod.POST,value ="/products")
public void addProduct(@RequestBody Product product){
productService.addProduct(product);
}
Service method:
public void addProduct(Product product){
productRepository.save(product);
}
I have commented in the fields where I need help for the addProduct() methods.
Controller tests:
package com.product.controllers;
import com.product.entities.Product;
import com.product.services.ProductService;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import java.util.ArrayList;
import java.util.List;
import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.when;
@ExtendWith(MockitoExtension.class)
class ProductControllerTest {
@InjectMocks
ProductController productController;
@Mock
ProductService productService;
@Test
public void getHomePage(){
String homePageText = "Welcome to the home page!";
assertEquals(homePageText,productController.getHomePage());
}
@Test
public void getAllProducts(){
Product product1 = new Product();
product1.setId("001");
product1.setName("TV");
product1.setPrice(999.99);
Product product2 = new Product();
product2.setId("002");
product2.setName("Mobile");
product2.setPrice(300D);
List<Product> listOfProducts = new ArrayList<>();
listOfProducts.add(product1);
listOfProducts.add(product2);
when(productService.getAllProducts()).thenReturn(listOfProducts);
assertEquals(listOfProducts,productController.getAllProducts());
}
@Test
public void getProductById(){
Product product = new Product();
product.setId("001");
product.setName("TV");
product.setPrice(999.99);
when(productService.getProductById("001")).thenReturn(product);
assertEquals(new ResponseEntity<Product> (product, HttpStatus.OK),productController.getProductById("001"));
}
@Test
public void addProduct() {
Product product = new Product();
product.setId("001");
product.setName("TV");
product.setPrice(999.99);
// need help with this
}
}
Service tests:
package com.product.services;
import com.product.entities.Product;
import com.product.repositories.ProductRepository;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import java.util.ArrayList;
import java.util.List;
import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.Mockito.when;
@ExtendWith(MockitoExtension.class)
public class ProductServiceTest {
@InjectMocks
ProductService productService;
@Mock
ProductRepository productRepository;
@Test
public void getAllProducts() {
Product product1 = new Product();
product1.setId("001");
product1.setName("TV");
product1.setPrice(999.99);
Product product2 = new Product();
product2.setId("002");
product2.setName("Mobile");
product2.setPrice(300D);
List<Product> listOfProducts = new ArrayList<>();
listOfProducts.add(product1);
listOfProducts.add(product2);
when(productRepository.findAll()).thenReturn(listOfProducts);
assertEquals(listOfProducts, productService.getAllProducts());
}
@Test
public void getProductById() {
Product product = new Product();
product.setId("001");
product.setName("TV");
product.setPrice(999.99);
when(productRepository.findById("001")).thenReturn(java.util.Optional.of(product));
assertEquals(product, productService.getProductById("001"));
}
@Test
public void addProduct() {
Product product = new Product();
product.setId("001");
product.setName("TV");
product.setPrice(999.99);
// need help with this
}
}
Solution
This code is quite simple so I'm not sure you need to unit test it. But if you want to, you can make use of your Mockito's mocks' verify
method. For example when testing addProduct
:
@InjectMocks
ProductService productService;
@Mock
ProductRepository productRepository;
// ...
@Test
public void testAddProduct() {
Product dummyProduct = new Product();
productService.addProduct(dummyProduct);
// eq() is from the Mockito matchers package
Mockito.verify(productRepository, Mockito.times(1)).save(eq(dummyProduct))
}
This verifies that save
was called on time on the mocked repository with an argument of dummyProduct
.
You also may want to check out Mockito "argument captors".
Answered By - phonaputer