{"id":6504,"date":"2020-11-19T03:04:04","date_gmt":"2020-11-19T08:04:04","guid":{"rendered":"http:\/\/springframework.guru\/?p=6504"},"modified":"2021-01-14T17:09:07","modified_gmt":"2021-01-14T22:09:07","slug":"testing-spring-boot-restful-services","status":"publish","type":"post","link":"https:\/\/springframework.guru\/testing-spring-boot-restful-services\/","title":{"rendered":"Testing Spring Boot RESTful Services"},"content":{"rendered":"<p>A Spring Boot RESTful service is typically divided into three layers: \u00a0Repository, Service, and Controller. This layering helps to <a href=\"http:\/\/springframework.guru\/principles-of-object-oriented-design\/single-responsibility-principle\/\">segregate<\/a> the RESTful application responsibilities and enabling loose coupling between the objects.<\/p>\n<p>When you develop a layered RESTful application, you will also need to test the different layers.<\/p>\n<p>In this post, I will discuss testing Spring Boot RESTful Services with Spring MVC Test and JUnit5.<\/p>\n<h2>The Maven POM<\/h2>\n<p>To start testing Spring Boot RESTful services, you need <code class=\"EnlighterJSRAW\" data-enlighter-language=\"java\" data-enlighter-theme=\"git\" data-enlighter-linenumbers=\"false\">spring-boot-starter-test<\/code>, which is a starter dependency for Spring Testing.<\/p>\n<p>This Spring Boot starter depenency also transitively brings in other testing dependencies such as <a href=\"https:\/\/www.baeldung.com\/mockito-series\"><code class=\"EnlighterJSRAW\" data-enlighter-language=\"java\" data-enlighter-theme=\"git\" data-enlighter-linenumbers=\"false\">Mockito<\/code><\/a>, <a href=\"https:\/\/junit.org\/junit5\/\"><code class=\"EnlighterJSRAW\" data-enlighter-language=\"java\" data-enlighter-theme=\"git\" data-enlighter-linenumbers=\"false\">JUnit<\/code><\/a>, <a href=\"https:\/\/mvnrepository.com\/artifact\/org.hamcrest\/hamcrest-all\"><code class=\"EnlighterJSRAW\" data-enlighter-language=\"java\" data-enlighter-theme=\"git\" data-enlighter-linenumbers=\"false\">Hamcrest<\/code><\/a>, <a href=\"https:\/\/mvnrepository.com\/artifact\/org.assertj\/assertj-core\"><code class=\"EnlighterJSRAW\" data-enlighter-language=\"java\" data-enlighter-theme=\"git\" data-enlighter-linenumbers=\"false\">AssertJ<\/code><\/a>.<\/p>\n<p>This is the dependency you need to add in the pom.xml file.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"java\" data-enlighter-theme=\"git\">&lt;dependency&gt;\r\n     &lt;groupId&gt;org.springframework.boot&lt;\/groupId&gt;\r\n     &lt;artifactId&gt;spring-boot-starter-test&lt;\/artifactId&gt;\r\n     &lt;scope&gt;test&lt;\/scope&gt;\r\n     &lt;exclusions&gt;\r\n         &lt;exclusion&gt;\r\n             &lt;groupId&gt;org.junit.vintage&lt;\/groupId&gt;\r\n             &lt;artifactId&gt;junit-vintage-engine&lt;\/artifactId&gt;\r\n         &lt;\/exclusion&gt;\r\n     &lt;\/exclusions&gt;\r\n&lt;\/dependency&gt;\r\n<\/pre>\n<h2>Testing the Repository Layer<\/h2>\n<p>This is the repository I will be testing.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"java\" data-enlighter-theme=\"git\">@Repository\r\npublic interface ProductRepository extends JpaRepository &lt;Product, Integer&gt; {\r\n\r\n}\r\n<\/pre>\n<p>Let\u2019s start writing the test class, <code class=\"EnlighterJSRAW\" data-enlighter-language=\"java\" data-enlighter-theme=\"git\" data-enlighter-linenumbers=\"false\">ProductRepositoryTest<\/code> .<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"java\" data-enlighter-theme=\"git\">@ExtendWith(SpringExtension.class)\r\n@DataJpaTest\r\nclass ProductRepositoryTest {<\/pre>\n<p>The first statement annotates the class with <code class=\"EnlighterJSRAW\" data-enlighter-language=\"java\" data-enlighter-theme=\"git\" data-enlighter-linenumbers=\"false\">@ExtendWith(SpringExtension.class)<\/code>.\u00a0 This integrates the Spring test context framework into the <a href=\"https:\/\/junit.org\/junit5\/docs\/current\/user-guide\/\">JUnit 5<\/a> Jupiter programming model.<\/p>\n<p>Our test will be an integration test as an external database is used. Being an integration test, we need to load the Spring context in our test. We can do that using the <code class=\"EnlighterJSRAW\" data-enlighter-language=\"java\" data-enlighter-theme=\"git\" data-enlighter-linenumbers=\"false\">@SpringBootTest<\/code> annotation.<\/p>\n<p>However, loading the entire Spring context is heavy and makes the tests slow.<\/p>\n<p>Therefore, we will only load the Spring Data JPA slice of the Spring context. The <code class=\"EnlighterJSRAW\" data-enlighter-language=\"java\" data-enlighter-theme=\"git\" data-enlighter-linenumbers=\"false\">@DataJpaTest<\/code> annotation in the code does exactly that.<\/p>\n<p>Next, let\u2019s autowire the <code class=\"EnlighterJSRAW\" data-enlighter-language=\"java\" data-enlighter-theme=\"git\" data-enlighter-linenumbers=\"false\">ProductRepository<\/code> that we will test and write the <code class=\"EnlighterJSRAW\" data-enlighter-language=\"java\" data-enlighter-theme=\"git\" data-enlighter-linenumbers=\"false\">setup() <\/code> and <code class=\"EnlighterJSRAW\" data-enlighter-language=\"java\" data-enlighter-theme=\"git\" data-enlighter-linenumbers=\"false\">teardown()<\/code> methods.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"java\" data-enlighter-theme=\"git\">    @Autowired\r\n    private ProductRepository productRepository;\r\n    private Product product;\r\n\r\n    @BeforeEach\r\n    public void setUp() {\r\n\r\n        product = new Product(1,\"Bat\",2500);\r\n    }\r\n\r\n    @AfterEach\r\n    public void tearDown() {\r\n        productRepository.deleteAll();\r\n        product = null;\r\n    }\r\n<\/pre>\n<h3>Test Case for Saving a Product<\/h3>\n<p>Let\u2019s start writing a test for saving a product.<\/p>\n<p>The test code is this.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"java\" data-enlighter-theme=\"git\">@Test\r\npublic void givenProductToAddShouldReturnAddedProduct(){\r\n\r\n     productRepository.save(product);\r\n     Product fetchedProduct = productRepository.findById(product.getId()).get();\r\n\r\n     assertEquals(1, fetchedProduct.getId());\r\n}\r\n<\/pre>\n<h3>Test Case to Retrieve the List of Products<\/h3>\n<p>This test code tests for the retrieval of all products.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"java\" data-enlighter-theme=\"git\">@Test\r\npublic void GivenGetAllProductShouldReturnListOfAllProducts(){\r\n     Product product1 = new Product(1,\"ball\",400);\r\n     Product product2 = new Product(2,\"bat\",500);\r\n     productRepository.save(product1);\r\n     productRepository.save(product2);\r\n\r\n     List&lt;Product&gt; productList = (List&lt;Product&gt;) productRepository.findAll();\r\n     assertEquals(\"bat\", productList.get(1).getName());\r\n\r\n}<\/pre>\n<h3>Test Case to Retrieve Product by Id<\/h3>\n<p>This test code tests for retrieving a product by ID.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"java\" data-enlighter-theme=\"git\">@Test\r\npublic void givenIdThenShouldReturnProductOfThatId() {\r\n     Product product1 = new Product(1,\"bat\",3000);\r\n     Product product2 = productRepository.save(product1);\r\n\r\n     Optional&lt;Product&gt; optional =\u00a0 productRepository.findById(product2.getId());\r\n     assertEquals(product2.getId(), optional.get().getId());\r\n     assertEquals(product2.getName(), optional.get().getName());\r\n}<\/pre>\n<h3>Test Case to Delete a Product by Id<\/h3>\n<p>Finally, this test code tests for the deletion of products.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"java\" data-enlighter-theme=\"git\">@Test\r\npublic void givenIdTODeleteThenShouldDeleteTheProduct() {\r\n      Product product = new Product(4,\u00a0 \"pen\",160);\r\n      productRepository.save(product);\r\n      productRepository.deleteById(product.getId());\r\n      Optional optional = productRepository.findById(product.getId());\r\n      assertEquals(Optional.empty(), optional);\r\n}\r\n<\/pre>\n<p>Let\u2019s run the tests, as you can see from the output provided below, all the test case passes.<\/p>\n<p><a href=\"http:\/\/springframework.guru\/wp-content\/uploads\/2020\/11\/Screenshot-201.png\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-large wp-image-6506\" src=\"http:\/\/springframework.guru\/wp-content\/uploads\/2020\/11\/Screenshot-201-1024x191.png\" alt=\"test cases for repository \" width=\"1024\" height=\"191\" srcset=\"https:\/\/springframework.guru\/wp-content\/uploads\/2020\/11\/Screenshot-201-1024x191.png 1024w, https:\/\/springframework.guru\/wp-content\/uploads\/2020\/11\/Screenshot-201-300x56.png 300w, https:\/\/springframework.guru\/wp-content\/uploads\/2020\/11\/Screenshot-201-768x143.png 768w, https:\/\/springframework.guru\/wp-content\/uploads\/2020\/11\/Screenshot-201-848x158.png 848w, https:\/\/springframework.guru\/wp-content\/uploads\/2020\/11\/Screenshot-201-410x76.png 410w, https:\/\/springframework.guru\/wp-content\/uploads\/2020\/11\/Screenshot-201.png 1365w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><\/a><\/p>\n<h2>Testing the Service Layer<\/h2>\n<p>The Service layer class <code class=\"EnlighterJSRAW\" data-enlighter-language=\"java\" data-enlighter-theme=\"git\" data-enlighter-linenumbers=\"false\">ProductServiceImpl<\/code> is responsible for using the repository for performing CRUD operation.<\/p>\n<p>This is the code of the <code class=\"EnlighterJSRAW\" data-enlighter-language=\"java\" data-enlighter-theme=\"git\" data-enlighter-linenumbers=\"false\">ProductServiceImpl<\/code> class.<\/p>\n<p><strong>ProductServiceImpl.java<\/strong><\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"java\" data-enlighter-theme=\"git\">@Service\r\npublic class ProductServiceImpl implements ProductService{\r\n\r\n    private ProductRepository productRepository;\r\n\r\n    @Autowired\r\n    public void setProductRepository(ProductRepository productRepository){\r\n          this.productRepository =productRepository;\r\n    }\r\n\r\n    @Override\r\n    public Product addProduct(Product product) throws ProductAlreadyExistsException {\r\n        if(productRepository.existsById(product.getId())){\r\n            throw new ProductAlreadyExistsException();\r\n        }\r\n        return productRepository.save(product);\r\n    }\r\n\r\n    @Override\r\n    public List&lt;Product&gt; getAllProducts() {\r\n\r\n        return (List&lt;Product&gt;) productRepository.findAll();\r\n    }\r\n\r\n    @Override\r\n    public Product getProductByid(int id) {\r\n        return productRepository.findById(id).orElse(null);\r\n    }\r\n\r\n    @Override\r\n    public Product deleteProductById(int id) {\r\n        Product product = null;\r\n        Optional optional = productRepository.findById(id);\r\n        if (optional.isPresent()) {\r\n            product = productRepository.findById(id).get();\r\n            productRepository.deleteById(id);\r\n        }\r\n        return product;\r\n    }\r\n<\/pre>\n<p>We will write pure unit tests of the service implementation \u2013 <code class=\"EnlighterJSRAW\" data-enlighter-language=\"java\" data-enlighter-theme=\"git\" data-enlighter-linenumbers=\"false\">ProductServiceImpl<\/code>. The reason is that unit tests are super-fast and therefore cuts down developers&#8217; time.<\/p>\n<p>Note that in unit testing, when we have external dependencies, we mock the dependencies.\u00a0 So in this example, we will mock the <code class=\"EnlighterJSRAW\" data-enlighter-language=\"java\" data-enlighter-theme=\"git\" data-enlighter-linenumbers=\"false\">ProductRepository<\/code> class.<\/p>\n<p>For more information on mocking, refer to my post <a href=\"http:\/\/springframework.guru\/mocking-unit-tests-mockito\/\" target=\"_blank\" rel=\"noopener noreferrer\">Mocking in Unit Tests with Mockito<\/a>.<\/p>\n<p>Let&#8217;s start writing the code. The code for the unit test is this.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"java\" data-enlighter-theme=\"git\">@ExtendWith(MockitoExtension.class)\r\nclass ProductServiceTest {\r\n\r\n\r\n    @Mock\r\n    private ProductRepository productRepository;\r\n\r\n    @Autowired\r\n    @InjectMocks\r\n    private ProductServiceImpl productService;\r\n    private Product product1;\r\n    private Product product2;\r\n    List&lt;Product&gt; productList;\r\n\r\n    @BeforeEach\r\n    public void setUp() {\r\n    productList = new ArrayList&lt;&gt;();\r\n    product1 = new Product(1, \"bread\",20);\r\n    product2 = new Product(2, \"jam\",200);\r\n    productList.add(product1);\r\n    productList.add(product2);\r\n    }\r\n\r\n    @AfterEach\r\n    public void tearDown() {\r\n    product1 = product2 = null;\r\n    productList = null;\r\n    }\r\n<\/pre>\n<p>Line 1 uses annotation. This <code class=\"EnlighterJSRAW\" data-enlighter-language=\"java\" data-enlighter-theme=\"git\" data-enlighter-linenumbers=\"false\">MockitoExtension<\/code> is a part of the Mockito library that is used to perform mocking. It initializes mocks in test classes.<\/p>\n<p>Then, Line5 \u2013 Line 6 uses the <code class=\"EnlighterJSRAW\" data-enlighter-language=\"java\" data-enlighter-theme=\"git\" data-enlighter-linenumbers=\"false\">@Mock<\/code> annotation on <code class=\"EnlighterJSRAW\" data-enlighter-language=\"java\" data-enlighter-theme=\"git\" data-enlighter-linenumbers=\"false\">ProductRepository<\/code>. At run time, Mockito will create a mock of <code class=\"EnlighterJSRAW\" data-enlighter-language=\"java\" data-enlighter-theme=\"git\" data-enlighter-linenumbers=\"false\">ProductRepository<\/code>.<\/p>\n<p>Finally, Line 8-Line10 uses the <code class=\"EnlighterJSRAW\" data-enlighter-language=\"java\" data-enlighter-theme=\"git\" data-enlighter-linenumbers=\"false\">@Autowired <\/code> annotation to autowire in <code class=\"EnlighterJSRAW\" data-enlighter-language=\"java\" data-enlighter-theme=\"git\" data-enlighter-linenumbers=\"false\">ProductServiceImpl<\/code> . The <code class=\"EnlighterJSRAW\" data-enlighter-language=\"java\" data-enlighter-theme=\"git\" data-enlighter-linenumbers=\"false\">@InjectMock<\/code> the annotation will initialize the \u00a0<code class=\"EnlighterJSRAW\" data-enlighter-language=\"java\" data-enlighter-theme=\"git\" data-enlighter-linenumbers=\"false\">ProductServiceImpl<\/code> \u00a0object with the <code class=\"EnlighterJSRAW\" data-enlighter-language=\"java\" data-enlighter-theme=\"git\" data-enlighter-linenumbers=\"false\">ProductRepository<\/code> mock.<\/p>\n<h3>Test Case for Saving a Product<\/h3>\n<p>The test code\u00a0for saving a product is this.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"java\" data-enlighter-theme=\"git\">@Test\r\nvoid givenProductToAddShouldReturnAddedProduct() throws ProductAlreadyExistsException{\r\n\r\n     \/\/stubbing\r\n     when(productRepository.save(any())).thenReturn(product1);\r\n     productService.addProduct(product1);\r\n     verify(productRepository,times(1)).save(any());\r\n\r\n}\r\n<\/pre>\n<h3>Test Code for Retrieval of all Products<\/h3>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"java\" data-enlighter-theme=\"git\">@Test\r\npublic void GivenGetAllUsersShouldReturnListOfAllUsers(){\r\n     productRepository.save(product1);\r\n    \/\/stubbing mock to return specific data\r\n    when(productRepository.findAll()).thenReturn(productList);\r\n    List&lt;Product&gt; productList1 =productService.getAllProducts();\r\n    assertEquals(productList1,productList);\r\n    verify(productRepository,times(1)).save(product1);\r\n    verify(productRepository,times(1)).findAll();\r\n}\r\n<\/pre>\n<h3>Test Case to Retrieve a Product by Id<\/h3>\n<p>The test code which tests for retrieving a product by ID is this.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"java\" data-enlighter-theme=\"git\">@Test\r\npublic void givenIdThenShouldReturnProductOfThatId() {\r\n   Mockito.when(productRepository.findById(1)).thenReturn(Optional.ofNullable(product1));\r\n   assertThat(productService.getProductByid(product1.getId())).isEqualTo(product1);\r\n}\r\n<\/pre>\n<h3>Test Case to Delete a Product by Id<\/h3>\n<p>The test code for deleting a product of the respective id.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"java\" data-enlighter-theme=\"git\">@Test\r\npublic void givenIdTODeleteThenShouldDeleteTheProduct(){\r\n    when(productService.deleteProductById(product1.getId())).thenReturn(product1);\r\n\/\/assertThat(productService.);\r\n    verify(productRepository,times(1)).findAll();\r\n\r\n}\r\n<\/pre>\n<p>Let\u2019s run the tests.<\/p>\n<p>As you can see from the output provided below, all the test cases pass.<\/p>\n<p><a href=\"http:\/\/springframework.guru\/wp-content\/uploads\/2020\/11\/Screenshot-203.png\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone wp-image-6512 size-large\" src=\"http:\/\/springframework.guru\/wp-content\/uploads\/2020\/11\/Screenshot-203-1024x189.png\" alt=\"junit test cases for service\" width=\"1024\" height=\"189\" srcset=\"https:\/\/springframework.guru\/wp-content\/uploads\/2020\/11\/Screenshot-203-1024x189.png 1024w, https:\/\/springframework.guru\/wp-content\/uploads\/2020\/11\/Screenshot-203-300x55.png 300w, https:\/\/springframework.guru\/wp-content\/uploads\/2020\/11\/Screenshot-203-768x142.png 768w, https:\/\/springframework.guru\/wp-content\/uploads\/2020\/11\/Screenshot-203-848x157.png 848w, https:\/\/springframework.guru\/wp-content\/uploads\/2020\/11\/Screenshot-203-410x76.png 410w, https:\/\/springframework.guru\/wp-content\/uploads\/2020\/11\/Screenshot-203.png 1359w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><\/a><\/p>\n<h2>Testing the Controller Layer<\/h2>\n<p>We will also write a pure unit test for the controller.<\/p>\n<p>The code of the <strong>ProductController.java<\/strong> class that we will test is this.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"java\" data-enlighter-theme=\"git\">@RestController\r\n@RequestMapping(\"api\/v1\")\r\npublic class ProductController {\r\n    private ProductService productService;\r\n\r\n    public ProductController(ProductService productService) {\r\n        this.productService = productService;\r\n    }\r\n\r\n    @PostMapping(\"product\")\r\n    public ResponseEntity&lt;Product&gt; addProduct(@RequestBody Product product) throws ProductAlreadyExistsException {\r\n        Product saveProduct = productService.addProduct(product);\r\n        return new ResponseEntity&lt;&gt;(saveProduct, HttpStatus.CREATED);\r\n    }\r\n\r\n    @GetMapping(\"products\")\r\n    public ResponseEntity&lt;List&lt;Product&gt;&gt; getAllProducts(){\r\n\r\n        return new ResponseEntity&lt;List&lt;Product&gt;&gt;(\r\n                (List &lt;Product&gt;) productService.getAllProducts(),HttpStatus.OK);\r\n    }\r\n\r\n    @GetMapping(\"product\/{id}\")\r\n    public ResponseEntity&lt;Product&gt; getProductById(@PathVariable(\"id\") int id){\r\n        return new ResponseEntity&lt;&gt;(productService.getProductByid(id),HttpStatus.OK);\r\n    }\r\n\r\n\r\n    @DeleteMapping(\"product\/{id}\")\r\n        public ResponseEntity&lt;Product&gt; deleteProduct(@PathVariable(\"id\") int id) {\r\n        ResponseEntity responseEntity;\r\n        Product deletedProduct = productService.deleteProductById(id);\r\n        responseEntity = new ResponseEntity&lt;Product&gt;(deletedProduct, HttpStatus.OK);\r\n\r\n        return responseEntity;\r\n   }\r\n\r\n}\r\n<\/pre>\n<p>As you can see in the preceding code, the controller has a dependency on the service class, <code class=\"EnlighterJSRAW\" data-enlighter-language=\"java\" data-enlighter-theme=\"git\" data-enlighter-linenumbers=\"false\">ProductService<\/code>.<\/p>\n<p>So in our test, we will use Mockito to mock <code class=\"EnlighterJSRAW\" data-enlighter-language=\"java\" data-enlighter-theme=\"git\" data-enlighter-linenumbers=\"false\">ProductService<\/code> and inject a mock on <code class=\"EnlighterJSRAW\" data-enlighter-language=\"java\" data-enlighter-theme=\"git\" data-enlighter-linenumbers=\"false\">ProductController<\/code>.<\/p>\n<p>Now, let&#8217;s start writing the test class.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"java\" data-enlighter-theme=\"git\">@ExtendWith(MockitoExtension.class)\r\nclass ProductControllerTest {\r\n\r\n   @Mock\r\n   private ProductService productService;\r\n   private Product product;\r\n   private List&lt;Product&gt; productList;\r\n\r\n   @InjectMocks\r\n   private ProductController productController;\r\n\r\n   @Autowired\r\n   private MockMvc mockMvc;\r\n\r\n   @BeforeEach\r\n   public void setup(){\r\n   product = new Product(1,\"ball\",670);\r\n   mockMvc = MockMvcBuilders.standaloneSetup(productController).build();\r\n   }\r\n\r\n   @AfterEach\r\n   void tearDown() {\r\n   product = null;\r\n}\r\n<\/pre>\n<p>Line 4-Line5 uses the <code class=\"EnlighterJSRAW\" data-enlighter-language=\"java\" data-enlighter-theme=\"git\" data-enlighter-linenumbers=\"false\">@Mock<\/code> annotation on <code class=\"EnlighterJSRAW\" data-enlighter-language=\"java\" data-enlighter-theme=\"git\" data-enlighter-linenumbers=\"false\">ProductService<\/code> . At run time, Mockito will create a mock of <code class=\"EnlighterJSRAW\" data-enlighter-language=\"java\" data-enlighter-theme=\"git\" data-enlighter-linenumbers=\"false\">ProductService<\/code>.<\/p>\n<p>Next, Line 12-Line13 uses the <code class=\"EnlighterJSRAW\" data-enlighter-language=\"java\" data-enlighter-theme=\"git\" data-enlighter-linenumbers=\"false\">@Autowired<\/code> annotation to autowire in <code class=\"EnlighterJSRAW\" data-enlighter-language=\"java\" data-enlighter-theme=\"git\" data-enlighter-linenumbers=\"false\">MockMvc<\/code>. The <code class=\"EnlighterJSRAW\" data-enlighter-language=\"java\" data-enlighter-theme=\"git\" data-enlighter-linenumbers=\"false\">@InjectMock<\/code> annotation will initialize the \u00a0<code class=\"EnlighterJSRAW\" data-enlighter-language=\"java\" data-enlighter-theme=\"git\" data-enlighter-linenumbers=\"false\">ProductController<\/code> object.<\/p>\n<p>We need to send HTTP requests to the controller from our test class to assert they are responding as expected. For that, Line 18 uses\u00a0 <code class=\"EnlighterJSRAW\" data-enlighter-language=\"java\" data-enlighter-theme=\"git\" data-enlighter-linenumbers=\"false\">MockMvc<\/code>.<\/p>\n<p><code class=\"EnlighterJSRAW\" data-enlighter-language=\"java\" data-enlighter-theme=\"git\" data-enlighter-linenumbers=\"false\">MockMvc<\/code> provides a powerful way to mock Spring MVC.\u00a0 Through <code class=\"EnlighterJSRAW\" data-enlighter-language=\"java\" data-enlighter-theme=\"git\" data-enlighter-linenumbers=\"false\">@MockMvc<\/code> you can send <code class=\"EnlighterJSRAW\" data-enlighter-language=\"java\" data-enlighter-theme=\"git\" data-enlighter-linenumbers=\"false\">MockHttp<\/code> request to a controller and test how the controller responds.<\/p>\n<p>You can create instance of <code class=\"EnlighterJSRAW\" data-enlighter-language=\"java\" data-enlighter-theme=\"git\" data-enlighter-linenumbers=\"false\">mockMvc<\/code>\u00a0 through two methods of <code class=\"EnlighterJSRAW\" data-enlighter-language=\"java\" data-enlighter-theme=\"git\" data-enlighter-linenumbers=\"false\">MockMvcBuilders<\/code>. I have used <code class=\"EnlighterJSRAW\" data-enlighter-language=\"java\" data-enlighter-theme=\"git\" data-enlighter-linenumbers=\"false\">standaloneSetup<\/code> which registers the controller instances.\u00a0 The other one is the <code class=\"EnlighterJSRAW\" data-enlighter-language=\"java\" data-enlighter-theme=\"git\" data-enlighter-linenumbers=\"false\">webappContextSetup<\/code> method.<\/p>\n<h3>Test Case to Post a Product<\/h3>\n<p>Let\u2019s write a test for posting a product.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"java\" data-enlighter-theme=\"git\">@Test\r\npublic void PostMappingOfProduct() throws Exception{\r\n   when(productService.addProduct(any())).thenReturn(product);\r\n   mockMvc.perform(post(\"\/api\/v1\/product\").\r\n           contentType(MediaType.APPLICATION_JSON).\r\n           content(asJsonString(product))).\r\n           andExpect(status().isCreated());\r\n   verify(productService,times(1)).addProduct(any());\r\n}<\/pre>\n<p>In-Line 4-Line 7, <code class=\"EnlighterJSRAW\" data-enlighter-language=\"java\" data-enlighter-theme=\"git\" data-enlighter-linenumbers=\"false\">mockMvc<\/code> performs a post-operation of product on the URL <code class=\"EnlighterJSRAW\" data-enlighter-language=\"java\" data-enlighter-theme=\"git\" data-enlighter-linenumbers=\"false\">\"\/api\/v1\/product\" <\/code>\u00a0 whose content type is\u00a0 <code class=\"EnlighterJSRAW\" data-enlighter-language=\"java\" data-enlighter-theme=\"git\" data-enlighter-linenumbers=\"false\">APPLICATION_JSON<\/code>. \u00a0The status is <code class=\"EnlighterJSRAW\" data-enlighter-language=\"java\" data-enlighter-theme=\"git\" data-enlighter-linenumbers=\"false\">isCreated()<\/code>.<\/p>\n<h3>Test Case to Retrieve all Products<\/h3>\n<p>This test uses <code class=\"EnlighterJSRAW\" data-enlighter-language=\"java\" data-enlighter-theme=\"git\" data-enlighter-linenumbers=\"false\">mockMvc<\/code> to send a GET request to retrieve all products<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"java\" data-enlighter-theme=\"git\">@Test\r\npublic void GetMappingOfAllProduct() throws Exception {\r\n    when(productService.getAllProducts()).thenReturn(productList);\r\n    mockMvc.perform(MockMvcRequestBuilders.get(\"\/api\/v1\/products\").\r\n                   contentType(MediaType.APPLICATION_JSON).\r\n                   content(asJsonString(product))).\r\n                   andDo(MockMvcResultHandlers.print());\r\n    verify(productService).getAllProducts();\r\n    verify(productService,times(1)).getAllProducts();\r\n}\r\n<\/pre>\n<p>In-Line 4-Line 7, <code class=\"EnlighterJSRAW\" data-enlighter-language=\"java\" data-enlighter-theme=\"git\" data-enlighter-linenumbers=\"false\">mockMvc<\/code> performs a GET request to retrieve all products from the URL <code class=\"EnlighterJSRAW\" data-enlighter-language=\"java\" data-enlighter-theme=\"git\" data-enlighter-linenumbers=\"false\">\"\/api\/v1\/products \" <\/code> whose content type is <code class=\"EnlighterJSRAW\" data-enlighter-language=\"java\" data-enlighter-theme=\"git\" data-enlighter-linenumbers=\"false\">Json<\/code>. The content is <code class=\"EnlighterJSRAW\" data-enlighter-language=\"java\" data-enlighter-theme=\"git\" data-enlighter-linenumbers=\"false\">JsonString<\/code> of product details.<\/p>\n<p>This is the output on running the test.<\/p>\n<h3><a href=\"http:\/\/springframework.guru\/wp-content\/uploads\/2020\/11\/Screenshot-219-1.png\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-large wp-image-6567\" src=\"http:\/\/springframework.guru\/wp-content\/uploads\/2020\/11\/Screenshot-219-1-1024x560.png\" alt=\"retrieving all products\" width=\"1024\" height=\"560\" srcset=\"https:\/\/springframework.guru\/wp-content\/uploads\/2020\/11\/Screenshot-219-1-1024x560.png 1024w, https:\/\/springframework.guru\/wp-content\/uploads\/2020\/11\/Screenshot-219-1-300x164.png 300w, https:\/\/springframework.guru\/wp-content\/uploads\/2020\/11\/Screenshot-219-1-768x420.png 768w, https:\/\/springframework.guru\/wp-content\/uploads\/2020\/11\/Screenshot-219-1-848x464.png 848w, https:\/\/springframework.guru\/wp-content\/uploads\/2020\/11\/Screenshot-219-1-410x224.png 410w, https:\/\/springframework.guru\/wp-content\/uploads\/2020\/11\/Screenshot-219-1.png 1058w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><\/a><\/h3>\n<h3>Test Case to Retrieve Product by Id<\/h3>\n<p>This test uses <code class=\"EnlighterJSRAW\" data-enlighter-language=\"java\" data-enlighter-theme=\"git\" data-enlighter-linenumbers=\"false\">mockMvc<\/code> to send a GET request to retrieve a product with a given id.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"java\" data-enlighter-theme=\"git\">@Test\r\npublic void GetMappingOfProductShouldReturnRespectiveProducct() throws Exception {\r\n    when(productService.getProductByid(product.getId())).thenReturn(product);\r\n    mockMvc.perform(get(\"\/api\/v1\/product\/1\").\r\n           contentType(MediaType.APPLICATION_JSON).\r\n           content(asJsonString(product))).\r\n           andExpect(MockMvcResultMatchers.status().isOk()).\r\n           andDo(MockMvcResultHandlers.print());\r\n}<\/pre>\n<p>Similarly, in Line 4-Line 8, <code class=\"EnlighterJSRAW\" data-enlighter-language=\"java\" data-enlighter-theme=\"git\" data-enlighter-linenumbers=\"false\">mockmvc<\/code> performs a GET request to retrieve a product with given product id 1 from the URL <code class=\"EnlighterJSRAW\" data-enlighter-language=\"java\" data-enlighter-theme=\"git\" data-enlighter-linenumbers=\"false\">\"\/api\/v1\/product\/1 \" <\/code>. Its content type is <code class=\"EnlighterJSRAW\" data-enlighter-language=\"java\" data-enlighter-theme=\"git\" data-enlighter-linenumbers=\"false\">Json<\/code> and content is <code class=\"EnlighterJSRAW\" data-enlighter-language=\"java\" data-enlighter-theme=\"git\" data-enlighter-linenumbers=\"false\">JsonString<\/code> of product details.<\/p>\n<p>The output on running the test is this.<\/p>\n<p><a href=\"http:\/\/springframework.guru\/wp-content\/uploads\/2020\/11\/Screenshot-220.png\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-large wp-image-6568\" src=\"http:\/\/springframework.guru\/wp-content\/uploads\/2020\/11\/Screenshot-220-1024x541.png\" alt=\"product by id\" width=\"1024\" height=\"541\" srcset=\"https:\/\/springframework.guru\/wp-content\/uploads\/2020\/11\/Screenshot-220-1024x541.png 1024w, https:\/\/springframework.guru\/wp-content\/uploads\/2020\/11\/Screenshot-220-300x158.png 300w, https:\/\/springframework.guru\/wp-content\/uploads\/2020\/11\/Screenshot-220-768x406.png 768w, https:\/\/springframework.guru\/wp-content\/uploads\/2020\/11\/Screenshot-220-848x448.png 848w, https:\/\/springframework.guru\/wp-content\/uploads\/2020\/11\/Screenshot-220-410x216.png 410w, https:\/\/springframework.guru\/wp-content\/uploads\/2020\/11\/Screenshot-220.png 1053w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><\/a><\/p>\n<h3>Test Case to Delete a Product<\/h3>\n<p>This test uses <code class=\"EnlighterJSRAW\" data-enlighter-language=\"java\" data-enlighter-theme=\"git\" data-enlighter-linenumbers=\"false\">mockMvc<\/code> to send a DELETE request to delete a product with a given id.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"java\" data-enlighter-theme=\"git\">@Test\r\npublic void DeleteMappingUrlAndIdThenShouldReturnDeletedProduct() throws Exception {\r\n      when(productService.deleteProductById(product.getId())).thenReturn(product);\r\n      mockMvc.perform(delete(\"\/api\/v1\/product\/1\")\r\n      .contentType(MediaType.APPLICATION_JSON)\r\n      .content(asJsonString(product)))\r\n      .andExpect(MockMvcResultMatchers.status().isOk()).\r\n      andDo(MockMvcResultHandlers.print());\r\n}\r\n\r\npublic static String asJsonString(final Object obj){\r\n    try{\r\n        return new ObjectMapper().writeValueAsString(obj);\r\n    }catch (Exception e){\r\n           throw new RuntimeException(e);\r\n      }\r\n}<\/pre>\n<p>In Line 4-Line 8, <code class=\"EnlighterJSRAW\" data-enlighter-language=\"java\" data-enlighter-theme=\"git\" data-enlighter-linenumbers=\"false\">mockmvc<\/code> performs a DELETE request to delete a product with id 1 from the URL\u00a0 <code class=\"EnlighterJSRAW\" data-enlighter-language=\"java\" data-enlighter-theme=\"git\" data-enlighter-linenumbers=\"false\">\"\/api\/v1\/product\/1 \" <\/code> . The\u00a0 content type is <code class=\"EnlighterJSRAW\" data-enlighter-language=\"java\" data-enlighter-theme=\"git\" data-enlighter-linenumbers=\"false\">Json<\/code>. The content is <code class=\"EnlighterJSRAW\" data-enlighter-language=\"java\" data-enlighter-theme=\"git\" data-enlighter-linenumbers=\"false\">JsonString<\/code> of product details.<\/p>\n<p>Now, let&#8217;s run the test cases.<\/p>\n<p>The output shows below that all the test cases passed.<\/p>\n<p><a href=\"http:\/\/springframework.guru\/wp-content\/uploads\/2020\/11\/Screenshot-202.png\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone wp-image-6507\" src=\"http:\/\/springframework.guru\/wp-content\/uploads\/2020\/11\/Screenshot-202-1024x187.png\" alt=\"test cases for controller\" width=\"692\" height=\"126\" srcset=\"https:\/\/springframework.guru\/wp-content\/uploads\/2020\/11\/Screenshot-202-1024x187.png 1024w, https:\/\/springframework.guru\/wp-content\/uploads\/2020\/11\/Screenshot-202-300x55.png 300w, https:\/\/springframework.guru\/wp-content\/uploads\/2020\/11\/Screenshot-202-768x141.png 768w, https:\/\/springframework.guru\/wp-content\/uploads\/2020\/11\/Screenshot-202-848x155.png 848w, https:\/\/springframework.guru\/wp-content\/uploads\/2020\/11\/Screenshot-202-410x75.png 410w, https:\/\/springframework.guru\/wp-content\/uploads\/2020\/11\/Screenshot-202.png 1366w\" sizes=\"(max-width: 692px) 100vw, 692px\" \/><\/a><\/p>\n<p>You can find the source code of this post on <a href=\"https:\/\/github.com\/spring-framework-guru\/sfg-blog-posts\/tree\/master\/testingspringbootrestfulservice\" target=\"_blank\" rel=\"noopener noreferrer\">Github<\/a>.<\/p>\n<p>For in-depth knowledge of the Spring Framework check my Udemy Best Seller Course <a href=\"https:\/\/www.udemy.com\/course\/spring-framework-5-beginner-to-guru\/?referralCode=6D9ECD1F93988FEE5CE9\" target=\"_blank\" rel=\"noopener noreferrer\">Spring Framework 5: Beginner to Guru<\/a>.<\/p>\n<p>If you&#8217;d like to learn more about testing Spring Boot applications with Mockito and JUnit 5, checkout my course <a href=\"https:\/\/www.udemy.com\/course\/testing-spring-boot-beginner-to-guru\/?referralCode=EFFE87DDE96C8541B2EE\">Testing Spring Boot: Beginner to Guru<\/a>.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>A Spring Boot RESTful service is typically divided into three layers: \u00a0Repository, Service, and Controller. This layering helps to segregate the RESTful application responsibilities and enabling loose coupling between the objects. When you develop a layered RESTful application, you will also need to test the different layers. In this post, I will discuss testing Spring [&hellip;]<a href=\"https:\/\/springframework.guru\/testing-spring-boot-restful-services\/\" class=\"df-link-excerpt\">Continue reading<\/a><\/p>\n","protected":false},"author":111,"featured_media":4658,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_lmt_disableupdate":"","_lmt_disable":"","_monsterinsights_skip_tracking":false,"_monsterinsights_sitenote_active":false,"_monsterinsights_sitenote_note":"","_monsterinsights_sitenote_category":0,"_uf_show_specific_survey":0,"_uf_disable_surveys":false,"_jetpack_memberships_contains_paid_content":false,"footnotes":"","jetpack_publicize_message":"","jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":false,"jetpack_social_options":{"image_generator_settings":{"template":"highway","enabled":false},"version":2}},"categories":[33,21,104,182,330,85],"tags":[314,208,313,333,315,316,331,332],"class_list":["post-6504","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-junit","category-spring","category-spring-boot","category-spring-framework-5","category-spring-test","category-testing","tag-mock","tag-junit-5","tag-mockmvc","tag-spring-test","tag-testing-different-layers-of-spring-boot","tag-testing-repository","tag-testing-rest-controllers","tag-testing-rest-services"],"jetpack_publicize_connections":[],"aioseo_notices":[],"modified_by":"jt","jetpack_sharing_enabled":true,"jetpack_featured_media_url":"https:\/\/springframework.guru\/wp-content\/uploads\/2017\/07\/Testing-Spring-Boot03cweb.jpg","jetpack_shortlink":"https:\/\/wp.me\/p5BZrZ-1GU","_links":{"self":[{"href":"https:\/\/springframework.guru\/wp-json\/wp\/v2\/posts\/6504"}],"collection":[{"href":"https:\/\/springframework.guru\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/springframework.guru\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/springframework.guru\/wp-json\/wp\/v2\/users\/111"}],"replies":[{"embeddable":true,"href":"https:\/\/springframework.guru\/wp-json\/wp\/v2\/comments?post=6504"}],"version-history":[{"count":11,"href":"https:\/\/springframework.guru\/wp-json\/wp\/v2\/posts\/6504\/revisions"}],"predecessor-version":[{"id":6799,"href":"https:\/\/springframework.guru\/wp-json\/wp\/v2\/posts\/6504\/revisions\/6799"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/springframework.guru\/wp-json\/wp\/v2\/media\/4658"}],"wp:attachment":[{"href":"https:\/\/springframework.guru\/wp-json\/wp\/v2\/media?parent=6504"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/springframework.guru\/wp-json\/wp\/v2\/categories?post=6504"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/springframework.guru\/wp-json\/wp\/v2\/tags?post=6504"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}