I am trying to write test for my controller for my SPRING-BOOT CRUD operation project using junit5 and mocking. While running the test it is showing below error. Not able to understand what is the problem.
Error:-
10:24:51.840 [main] INFO org.springframework.test.web.servlet.TestDispatcherServlet -- Initializing Servlet ''
10:24:51.842 [main] INFO org.springframework.test.web.servlet.TestDispatcherServlet -- Completed initialization in 1 ms
10:24:51.865 [main] WARN org.springframework.web.servlet.PageNotFound -- No mapping for GET /content
java.lang.AssertionError: No value at JSON path "$.duration"
ContentController file:-
package com.example.sixth.controller;
import com.example.sixth.entity.Content;
import com.example.sixth.service.ContentService;
import org.springframework.web.bind.annotation.*;
import java.util.List;
import java.util.Optional;
@RestController
public class ContentController {
private final ContentService contentService;
public ContentController(ContentService contentService) {
this.contentService = contentService;
}
@GetMapping("/content")
public List<Content> show(){
return contentService.showAll();
}
@PostMapping("/content")
public String save(@RequestBody Content content){
return contentService.save(content);
}
@GetMapping("/content/title/{param}")
public List<Content> getContentStartWith(@PathVariable("param") String title){
return contentService.getContentStartWith(title);
}
@DeleteMapping("/content/{id}")
public String delete(@PathVariable Integer id){
return contentService.delete(id);
}
@GetMapping("/id")
public List<Content>getById(@RequestParam Integer minId,
@RequestParam Integer maxId){
return contentService.getById(minId,maxId);
}
@GetMapping("/content/{id}")
public Optional<Content> findById(@PathVariable Integer id){
return contentService.findById(id);
}
}
TestFile:-
package com.example.sixth;
import com.example.sixth.controller.ContentController;
import com.example.sixth.entity.Content;
import com.example.sixth.service.ContentService;
import com.example.sixth.service.ContentServiceImpl;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.http.MediaType;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.MockMvcBuilder;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
import org.springframework.test.web.servlet.result.MockMvcResultMatchers;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
//import org.powermock.api.mockito.PowerMockito;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import static org.hamcrest.Matchers.is;
import static org.junit.jupiter.api.Assertions.assertEquals;
@AutoConfigureMockMvc
//@SpringBootTest
public class ContentControllerTest {
@Autowired
MockMvc mockMvc;
@Mock
ContentService mockService;
@InjectMocks
ContentController contentController;
@BeforeEach
public void init(){
MockitoAnnotations.initMocks(this);
this.mockMvc= MockMvcBuilders.standaloneSetup(mockService).build();
}
@Test
public void testfindall() throws Exception {
Content content = (Content.builder()
.id(3)
.title("SECOND!!")
.duration(38)
.location("Bangalore").build());
List<Content> contentList = new ArrayList<>();
contentList.add(content);
Mockito.when(mockService.showAll()).thenReturn(contentList);
mockMvc.perform(MockMvcRequestBuilders.get("/content").contentType(MediaType.APPLICATION_JSON)).andExpect(MockMvcResultMatchers.jsonPath("$.duration",is(content.getDuration())));
// List<Content> actual=contentController.show();
// System.out.println(actual.get(0).toString());
// assertEquals(actual,contentList);
}
Btw when using assert it is working but with mockMvc it is showing error ..
As discussed in comments, you are trying to write a unit test for a single controller.
@WebMvcTest is the right tool for the job.
annotate your test with @WebMvcTest(Content controller.class) It will create spring context with web slice of the app.
You need to provide missing beans so that spring can create the instance of your controller. These are provided with @MockBean, not @Mock
Get requests do not have a body in http1 and http2. Remove content type in your request.
Lastly, you have MockMvc instance provided by WebMvcTest (this annotation is annotated with @AutoConfigureWebMvc), injected to your test with @Autowired. You were overwriting this instance with another, badly cofigured one in @BeforeEach. On top of that, you were also overwriting mocks. This is why entire BeforeEach needed to be deleted.