Cara memeriksa nilai di isi respons dengan mockMvc - AssertionError: Status yang diharapkan:‹201› tetapi:‹400›

Saya baru dalam tes penulisan dan saya mencoba menulis tes junit untuk kelas pengontrol saya menggunakan mockMvc.

Inilah kelas saya:

public class StudentDTO {

private final String firstName;
private final String lastName;
private final String JMBAG;
private final Integer numberOfECTS;
private final boolean tuitionShouldBePaid;}

Kelas komando

public class StudentCommand { 
@NotBlank (message = "First name must not be empty!")
private String firstName;

@NotBlank (message = "Last name must not be empty!")
private String lastName;


@NotNull(message = "Date of birth must be entered!")
@Past(message = "Date of birth must be in the past!")
private LocalDate dateOfBirth;

@NotBlank(message = "JMBAG must not be empty!")
@Pattern(message = "JMBAG must have 10 digits", regexp = "[\\d]{10}")
private String jmbag;

@NotNull(message = "Number of ECTS points must be entered!")
@PositiveOrZero(message = "Number of ECTS points must be entered as a positive integer!")
private Integer numberOfECTS;}

Kelas pengontrol:

@Secured({"ROLE_ADMIN"})
@PostMapping
public ResponseEntity<StudentDTO> save(@Valid @RequestBody final StudentCommand command){
    return studentService.save(command)
            .map(
                    studentDTO -> ResponseEntity
                            .status(HttpStatus.CREATED)
                            .body(studentDTO)
            )
            .orElseGet(
                    () -> ResponseEntity
                            .status(HttpStatus.CONFLICT)
                            .build()
            );
}

Kelas tes:

@SpringBootTest
@AutoConfigureMockMvc class StudentControllerTest {
@Autowired
private MockMvc mockMvc;

@MockBean
private StudentService studentServiceMock;

@Autowired
private ObjectMapper objectMapper;

private final String TEST_FIRST_NAME = "Marry";
private final String TEST_LAST_NAME = "Blinks";
private final String TEST_JMBAG = "0025478451";
private final Integer TEST_NUMBER_OF_ECTS = 55;
private final boolean TEST_TUITION_SHOULD_BE_PAID = true;
private final LocalDate TEST_DATE_OF_BIRTH = LocalDate.parse("1999-01-12");

@Test
void testSave() throws Exception {

    StudentCommand studentCommand = new StudentCommand(TEST_FIRST_NAME,TEST_LAST_NAME,TEST_DATE_OF_BIRTH,TEST_JMBAG,TEST_NUMBER_OF_ECTS);

    this.mockMvc.perform(
            post("/student")
                    .with(user("admin")
                            .password("test")
                            .roles("ADMIN")
                    )
                    .with(csrf())
            .contentType(MediaType.APPLICATION_JSON)
            .content(objectMapper.writeValueAsString(studentCommand))
            .accept(MediaType.APPLICATION_JSON)
    )
            .andExpect(status().isCreated())
            .andExpect(content().contentType(MediaType.APPLICATION_JSON))
            .andExpect(jsonPath("$.jmbag").value(TEST_JMBAG))
            .andExpect(jsonPath("$.firstName").value(TEST_FIRST_NAME))
            .andExpect(jsonPath("$.lastName").value(TEST_LAST_NAME));
}

Saya selalu mendapatkan tes gagal dengan kesalahan ini:


MockHttpServletRequest:
      HTTP Method = POST
      Request URI = /student
       Parameters = {_csrf=[30de7a8f-a3d5-429d-a778-beabd1a533da]}
          Headers = [Content-Type:"application/json;charset=UTF-8", Accept:"application/json", Content-Length:"272"]
             Body = {"firstName":"Marry","lastName":"Blinks","dateOfBirth":{"year":1999,"month":"JANUARY","monthValue":1,"dayOfMonth":12,"chronology":{"id":"ISO","calendarType":"iso8601"},"dayOfWeek":"TUESDAY","leapYear":false,"dayOfYear":12,"era":"CE"},"jmbag":"0025478451","numberOfECTS":55}
    Session Attrs = {}
Handler:
             Type = com.studapp.students.StudentController
           Method = com.studapp.students.StudentController#save(StudentCommand)
MockHttpServletResponse:
           Status = 400
    Error message = null
          Headers = [Vary:"Origin", "Access-Control-Request-Method", "Access-Control-Request-Headers", X-Content-Type-Options:"nosniff", X-XSS-Protection:"1; mode=block", Cache-Control:"no-cache, no-store, max-age=0, must-revalidate", Pragma:"no-cache", Expires:"0", X-Frame-Options:"DENY"]
     Content type = null
             Body = 
    Forwarded URL = null
   Redirected URL = null
          Cookies = []
java.lang.AssertionError: Status expected:<201> but was:<400>
Expected :201
Actual   :400

Saya tidak yakin mengapa itu gagal. Mengapa isi respons kosong? Saya tidak ingin memanggil layanan saya karena saya tidak mengujinya, tetapi saya merasa harus memanggilnya entah bagaimana caranya (tetapi sekali lagi, saya tidak menguji layanan tersebut). Setiap saran akan dihargai.


person Sinor Bodl    schedule 26.05.2020    source sumber
comment
apakah saya perlu mengejek layanan tersebut sehingga mockMvc bisa mendapatkan elemen darinya?   -  person Sinor Bodl    schedule 26.05.2020
comment
Bisakah Anda menunjukkan bagian atas kelas Tes? Anotasi mana yang Anda gunakan dan bagaimana cara melakukan autowire mockMvc dan objectMapper?   -  person Sebastian    schedule 26.05.2020
comment
@Sebastian @SpringBootTest @AutoConfigureMockMvc class StudentControllerTest { @Autowired private MockMvc mockMvc; private ObjectMapper objectMapper = new ObjectMapper(); Jadi objectMapper saya tidak diberi anotasi, saya tidak tahu itu membutuhkan sesuatu   -  person Sinor Bodl    schedule 26.05.2020
comment
jadi meskipun saya membubuhi keterangan objecMapper dengan @Autowire sekarang ini menunjukkan kesalahan Status yang diharapkan:‹201› tetapi tadinya:‹409›   -  person Sinor Bodl    schedule 26.05.2020
comment
dapatkah Anda menunjukkan bagaimana Anda membangun setiap nilai yang Anda berikan ke new StudentCommand(TEST_FIRST_NAME,TEST_LAST_NAME,TEST_DATE_OF_BIRTH,TEST_JMBAG,TEST_NUMBER_OF_ECTS); ini   -  person Hemant    schedule 26.05.2020
comment
@Hemant saya baru saja membuat variabel private final String TEST_FIRST_NAME = Marry; String akhir pribadi TEST_LAST_NAME = Berkedip; String akhir pribadi TEST_JMBAG = 0025478451; Integer akhir pribadi TEST_NUMBER_OF_ECTS = 55;   -  person Sinor Bodl    schedule 26.05.2020
comment
@Hemant, sekarang saya mengedit kelas pengontrol pengujian saya sehingga Anda dapat melihat tampilannya   -  person Sinor Bodl    schedule 26.05.2020
comment
409 tampaknya merupakan nilai yang benar ketika melihat kode Pengontrol Anda. Itu selalu lebih baik untuk melakukan Autowire ObjectMapper jika tidak maka tidak dikonfigurasi oleh Spring dengan cara yang sama seperti pada aplikasi yang sedang berjalan   -  person Sebastian    schedule 26.05.2020


Jawaban (1)


Anda harus menggunakan @Autowired pada ObjectMapper Anda untuk memastikannya dikonfigurasi dengan cara yang sama pada Spring seperti saat runtime aplikasi. Ini akan menjelaskan kesalahan 400 - Permintaan buruk yang Anda dapatkan.

Fakta bahwa ini adalah 409 - Konflik setelah pengkabelan otomatis ObjectMapper menunjukkan bahwa ini memang kesalahannya. Karena Anda tidak mengonfigurasi studentServiceMock dalam pengujian, 409 tampaknya merupakan jawaban yang tepat dari pengontrol, karena bagian orElseGet sedang dijalankan.

Jika saya tidak salah, Anda dapat sedikit memperkecil anotasi kelas pengujian dan hanya menggunakan @WebMvcTest. Ini seharusnya cukup untuk tes semacam ini dan seharusnya lebih cepat.

person Sebastian    schedule 26.05.2020
comment
bagaimana saya mengujinya ketika objek disimpan? - person Sinor Bodl; 26.05.2020
comment
Didorong oleh perilaku, akan terlihat seperti ini: given(studentServiceMock.save(any(StudentCommand.class).willReturn(studentCommand); Ini harus ditambahkan di bawah baris StudentCommand studentCommand = new StudentCommand...... ini dalam pengujian Anda. Tapi saya tidak menguji ini. - person Sebastian; 26.05.2020
comment
Oh, sepertinya save Anda mengembalikan Opsional. Dalam hal ini akan terlihat seperti ini: given(studentServiceMock.save(any(StudentCommand.class).willReturn(Optional.of(studentCommand)); - person Sebastian; 26.05.2020
comment
saya mendapat panggilan metode ambigu. Baik (Class‹StudentCommand›) di matcher maupun (Class‹StudentCommand›) di ArgumentMatchers cocok. - person Sinor Bodl; 26.05.2020
comment
Mereka seharusnya berada di kelas org.mockito.ArgumentMatchers. Anda cukup menambahkan impor statis: import static org.mockito.ArgumentMatchers.any; given berasal dari kelas org.mockito.BDDMockito. - person Sebastian; 26.05.2020
comment
saya mengubahnya sehingga mengembalikan StudentDTO. Saya perlu membuat objek StudentDto untuk itu dan tes sekarang lolos. Semoga tesnya oke. - person Sinor Bodl; 26.05.2020
comment
Ah, maaf, kesalahanku. Saya tidak memeriksa jenis pengembalian metode save dengan benar tetapi senang karena metode ini berfungsi sekarang :) - person Sebastian; 26.05.2020
comment
tidak masalah, hanya satu hal lagi yang ingin aku tanyakan padamu. Saat membuat studentServiceMock, haruskah saya menginisialisasinya dengan Mockito.mock(StudentService.class) -semua pengujian gagal jika saya melakukannya. Atau tidak apa-apa hanya dengan anotasi @MockBean - person Sinor Bodl; 26.05.2020
comment
bagaimana cara saya menulis tes untuk metode penyimpanan untuk konflik (atauElseGet di pengontrol)? mencoba dengan given(studentServiceMock.save(any(StudentCommand.class))).willReturn(Optional.empty()); tetapi dikatakan Status diharapkan:‹409› tetapi:‹400› - person Sinor Bodl; 26.05.2020
comment
Mari kita melanjutkan diskusi ini dalam chat. - person Sebastian; 27.05.2020