Search code examples
javaspringexceptionspring-mvc-test

WebMvcTest of @Controller with @RequestParam and status is not 200, but 400


i try to write @WebMvcTest:

@ExtendWith(SpringExtension.class)
@WebMvcTest(AudienceController.class)
class LectureControllerTest {

    @Autowired
    private MockMvc mockMvc;

    @MockBean
    private LectureService lectureService;
    @MockBean
    private GroupService groupService;
    @MockBean
    private TeacherService teacherService;
    @MockBean
    private StudentService studentService;

    @BeforeEach
    public void init() {
        this.mockMvc = MockMvcBuilders.standaloneSetup(new LectureController(lectureService, groupService, teacherService, studentService)).build();
    }
@Test
    void whenGetRequest_thenReturnTTForTeacherPage() throws Exception {
        Teacher teacher = new Teacher(1, "teacher", "first");
        Subject subject = new Subject(1, "first");
        LocalDateTime date = LocalDateTime.now();
        Audience audience = new Audience(1, 100);
        Group group = new Group(1, "group");
        Lecture lecture = new Lecture(1, teacher, subject, Arrays.asList(group), date);
        lecture.setAudience(audience);

        when(teacherService.findOne(1)).thenReturn(teacher);
        when(lectureService.findLecturesByTeacher(teacher, date, date)).thenReturn(Arrays.asList(lecture));

        mockMvc.perform(get("/lecture/TTForTeacher/{id}", 1)
                .param("startDay", date.toString())
                .param("endDay", date.toString()))
        .andDo(print())
        .andExpect(status().isOk())
        .andExpect(view().name("lecture/TTForTeacher"))
        .andExpect(forwardedUrl("lecture/TTForTeacher"))
        .andExpect(model().attribute("lectures", hasSize(1)))
        .andExpect(model().attribute("lectures", hasItem(
                allOf(
                        hasProperty("id", is(1)),
                        hasProperty("teacher", is(teacher)),
                        hasProperty("subject", is(subject)),
                        hasProperty("date", is(date)),
                        hasProperty("audience", is(audience)),
                        hasProperty("groups", is(Arrays.asList(group)))
                )
        )));

        verify(lectureService, times(1)).findLecturesByTeacher(teacher, date, date);
    }

for my controller:

@Controller
@RequestMapping("/lecture")
public class LectureController {

    private LectureService lectureService;
    private GroupService groupService;
    private TeacherService teacherService;
    private StudentService studentService;

    public LectureController(LectureService lectureService, GroupService groupService, TeacherService teacherService,
            StudentService studentService) {
        this.lectureService = lectureService;
        this.groupService = groupService;
        this.teacherService = teacherService;
        this.studentService = studentService;
    }
@GetMapping("/TTForTeacher/{id}")
    public String getTTForTeacher(@PathVariable("id") int id, @RequestParam(value = "startDay") LocalDateTime startDay,
            @RequestParam(value = "endDay") LocalDateTime endDay, Model model) {
        model.addAttribute("lectures",
                lectureService.findLecturesByTeacher(teacherService.findOne(id), startDay, endDay));
        return "lecture/TTForTeacher";
    }

But it has failures: "Status expected:<200> but was:<400>" and this in console:

MockHttpServletRequest:
      HTTP Method = GET
      Request URI = /lecture/TTForTeacher/1
       Parameters = {startDay=[10.05.2020, 10:00], endDay=[31.05.2020, 20:00]}
          Headers = []
             Body = <no character encoding set>
    Session Attrs = {}

Handler:
             Type = com.foxminded.university.controller.LectureController
           Method = com.foxminded.university.controller.LectureController#getTTForTeacher(int, LocalDateTime, LocalDateTime, Model)

Async:
    Async started = false
     Async result = null

Resolved Exception:
             Type = org.springframework.web.method.annotation.MethodArgumentTypeMismatchException

ModelAndView:
        View name = null
             View = null
            Model = null

FlashMap:
       Attributes = null

I tried not use .param("day", date.toString), to set string of several formats to this param, to use not .param, but i have this exception, can u help me with it. All other test of other methods are successful, but there are no @RequestParam in those methods. So how can i test methods like this


Solution

  • The controller is missing logic to parse data. Spring by default does not know how to convert the string to datetime object. There are 2 ways of solving this, one solution could be read date as String instead of LocalDate and then parse String to get the startDay and endDay, but there is a better way using @DateTimeFormat https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/format/annotation/DateTimeFormat.html

    Controller method becomes like this

    public String getTTForTeacher(@PathVariable("id") int id, @RequestParam(value = "startDay") @DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME) LocalDateTime startDay,
                                      @RequestParam(value = "endDay") @DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME) LocalDateTime endDay) {
    

    Test mockMvc can be left as is since you are doing LocalDateTime.now().toString()