Как написать модульный тест для контроллера при весенней загрузке - PullRequest
0 голосов
/ 10 мая 2019

Я новичок в модульном тестировании и TDD. Я хочу применить модульное тестирование для моего контроллера и класса обслуживания, которое я написал при загрузке.

Я реализовал тестовый класс с помощью учебника. Однако я не смог реализовать это успешно. Я включил свой текущий код.

Контроллер

@RestController
@RequestMapping("/api")
public class MyController {
    private static final Logger LOGGER = LoggerFactory.getLogger(AdminController.class);
    @Autowired
    MyService myService;

    @PostMapping("/create")
    public ResponseEntity<?> createUser(@RequestHeader("Authorization") String token, 
        @RequestBody User user){
        ResponseDTO finalResponse = new ResponseDTO();
        try {
            ResponseEntity<?> entity = myService.create(token, user);             
            finalResponse.setMessageCode(entity.getStatusCode());
            finalResponse.setMessage("Success");
            finalResponse.setError(false);
            ResponseEntity<ResponseDTO> finalEntity = ResponseEntity.ok().body(finalResponse);
        return finalEntity;
        } catch (Exception e) {      
            finalResponse.setMessageCode(HttpStatus.EXPECTATION_FAILED);
            finalResponse.setMessage(e.getMessage());
            finalResponse.setError(true);
            ResponseEntity<ResponseDTO> finalEntity = 
            ResponseEntity.ok().body(finalResponse);
            return finalEntity;
    }
}

ResponseDTO

public class ResponseDTO {
    private HttpStatus messageCode;
    private String message;
    private String messageDetail;
    private Object body;
    private boolean error;

    //setters and getters
}

Текущий класс испытаний

@RunWith(SpringRunner.class)
public class MyControllerTest {
    private MockMvc mockMvc;

    @InjectMocks
    private MyController myController;

    @Before
    public void setUp() throws Exception {
    mockMvc = MockMvcBuilders.standaloneSetup(myController).build();
    }

    @Test
    public void testCreateUser() throws Exception {
        mockMvc.perform(post("/api/create")
            .accept(MediaType.APPLICATION_JSON))
            .andExpect(status().isCreated())
            .andExpect(jsonPath("$.*", Matchers.hasSize(1)));
    }

}

Когда я запускаю тестовый класс, я получаю WARN Resolved [org.springframework.web.bind.MissingRequestHeaderException: Missing request header 'Authorization' for method parameter of type String]

Что я здесь не так делаю? Любая помощь будет благодарна.

Ответы [ 2 ]

2 голосов
/ 10 мая 2019

Есть несколько проблем с вашим тестом:

1. Запрос картографирования

@PostMapping("/create")
public ResponseEntity<?> createUser(
    @RequestHeader("Authorization") String token, 
    @RequestBody User user)

соответствует только POST запросам с заголовком HTTP с именем Authorization и телом запроса, которое можно сериализовать до User. Это не обязательно. Если они являются необязательными, вы должны явно объявить, что:

@PostMapping("/create")
public ResponseEntity<?> createUser(
   @RequestHeader(name = "Authorization", required = false) String token, 
   @RequestBody(required = false) User user) {

Предполагая, что они требуются, вы должны настроить MockMvc для отправки обоих на ваш контроллер:

    @Test
    public void testCreateUser() throws Exception {
        mockMvc.perform(
                post("/api/create")
                  .header("Authorization", "XYZ")
                  .content("{\"firstName\": \"James\", \"lastName\": \"Gosling\"}")
                  .accept(MediaType.APPLICATION_JSON)
                )
               .andExpect(status().isCreated())
               .andExpect(jsonPath("$.*", Matchers.hasSize(1)));
    }

здесь я предположил, что ваш User класс такой:

public class User {

    private String firstName;

    private String lastName;

    public String getFirstName() {
        return firstName;
    }

    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }

    public String getLastName() {
        return lastName;
    }

    public void setLastName(String lastName) {
        this.lastName = lastName;
    }
}

2. Content-Type заголовок

Кроме того, вы должны установить заголовок типа контента для вашего запроса MockMvc, в противном случае проверка не будет выполнена с 415 - Unsupported Media Type. Итак, ваш тест должен выглядеть так:

    @Test
    public void testCreateUser() throws Exception {
        mockMvc.perform(
                post("/api/create")
                  .header("Authorization", "XYZ")
                  .header("Content-Type", "application/json")
                  .content("{\"firstName\": \"James\", \"lastName\": \"Gosling\"}")
                  .accept(MediaType.APPLICATION_JSON)
                )
               .andExpect(status().isCreated())
               .andExpect(jsonPath("$.*", Matchers.hasSize(1)));
    }

3. Макетные зависимости

Кроме того, в своем тесте вы аннотировали MyController с помощью @InjectMocks, но вы не высмеивали его MyService' dependency. That will set the myService field of your controller to null . To fix that you need to mock MyService ':

@RunWith(SpringRunner.class)
public class MyControllerTest {

    private MockMvc mockMvc;

    // Mock
    @Mock
    private MyService myService;

    @InjectMocks
    private MyController myController;

    @Before
    public void setUp() throws Exception {
        mockMvc = MockMvcBuilders.standaloneSetup(myController).build();
    }

    @Test
    public void testCreateUser() throws Exception {
        // Configure mock myService
        when(myService.create(anyString(), any(User.class))).thenReturn(new ResponseEntity<>(HttpStatus.CREATED));

        mockMvc.perform(
                post("/api/create")
                  .header("Authorization", "XYZ")
                  .header("Content-Type", "application/json")
                  .content("{\"firstName\": \"James\", \"lastName\": \"Gosling\"}")
                  .accept(MediaType.APPLICATION_JSON)
                )
               .andExpect(status().isCreated())
               .andExpect(jsonPath("$.*", Matchers.hasSize(1)));
    }

}

4. MyService не удовлетворяет условиям испытаний

Когда все в порядке, ваш контроллер отвечает:

ResponseEntity<ResponseDTO> finalEntity = ResponseEntity.ok().body(finalResponse);

, который вернет код состояния 200. Таким образом, вы должны либо изменить свой тест, чтобы ожидать, что:

.andExpect(status().isOk())

или вам следует обновить контроллер, чтобы он возвращался с кодом состояния 201:

ResponseEntity<ResponseDTO> finalEntity = ResponseEntity.created(null).body(finalResponse);
2 голосов
/ 10 мая 2019

Ваш тест может выглядеть примерно так:

 @Test
public void testCreateUser() throws Exception {
    mockMvc.perform(post("/api/create")
        .accept(MediaType.APPLICATION_JSON)
        .header("AUTH_TOKEN", TOKEN)
        .content(ObjectToJsonUtil.convertObjectToJsonBytes(user)))
        .andExpect(status().isCreated())
        .andExpect(jsonPath("$.*", Matchers.hasSize(1)));
}

вам придется конвертировать объект user в json.Таким образом, вы создаете класс утилит для этого:

public class ObjectToJsonUtil {
    public static byte[] convertObjectToJsonBytes(Object object)
            throws IOException {
        ObjectMapper mapper = new ObjectMapper();
        mapper.setSerializationInclusion(JsonInclude.Include.NON_EMPTY);

        JavaTimeModule module = new JavaTimeModule();
        mapper.registerModule(module);

        return mapper.writeValueAsBytes(object);
    }

}

Надеюсь, это поможет!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...