Интеграционное тестирование контроллера обновления пользователя с MockMvc

Я пытаюсь проверить, правильно ли работает логика контроллера обновления пользователя, создав несколько простых интеграционных тестов с использованием MockMvc.

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

Проблема в том, как проверить, действительно ли пароль был обновлен до отката теста?

Я попытался вручную выполнить вход в систему до завершения теста, и если вход в систему с исходными учетными данными завершился неудачно, пароль был обновлен.

Самая простая часть теста проста:

@Test
  void WhenUserIsAdmin_UserCanUpdateAllFields() throws Exception {

    updatedUser.setPassword("newPassword");

    String jsonString = mapper.writeValueAsString(updatedUser);

    MockHttpServletRequestBuilder builder = TestRequestFactory.authorizationFactoryPUT(URI, "admin");
    mockMvc.perform(builder.contentType(MediaType.APPLICATION_JSON).content(jsonString))
        .andExpect(status().isOk())
        .andExpect(MockMvcResultMatchers.jsonPath("$.firstName").value("admin2"))
        .andExpect(MockMvcResultMatchers.jsonPath("$.surnamePaternal").value("admin2"))
        .andExpect(MockMvcResultMatchers.jsonPath("$.surnameMaternal").value("admin2"))
        .andExpect(MockMvcResultMatchers.jsonPath("$.roleName").value("User"))
        .andExpect(MockMvcResultMatchers.jsonPath("$.roleType").value("ROLE_USER"))
        .andExpect(MockMvcResultMatchers.jsonPath("$.created").isNotEmpty());
  }

и Фабрика выглядит так

public static MockHttpServletRequestBuilder authorizationFactoryPUT(String url, String user)
      throws JsonProcessingException {
    return MockMvcRequestBuilders.put(url)
        .header(HttpHeaders.AUTHORIZATION, doLogin(user, user));
  }

static String doLogin(String user, String pass) throws JsonProcessingException {
    LoginRequest loginRequest = new LoginRequest(user, pass);
    String resultAsJsonString = restTemplate.postForEntity(loginServer + "/login", loginRequest, String.class).getBody();
    LoginResponse loginResponse = mapper.readValue(Objects.requireNonNull(resultAsJsonString), LoginResponse.class);
    return loginResponse.getTokenType() + " " + loginResponse.getAccessToken();
  }

и внутри того же теста, который я пробовал

LoginRequest loginRequest = new LoginRequest(user, pass);
String resultAsJsonString = restTemplate.postForEntity(loginServer + "/login", loginRequest, String.class).getBody();
LoginResponse loginResponse = mapper.readValue(Objects.requireNonNull(resultAsJsonString), LoginResponse.class);

и если ответ не выполняется во время сопоставления или код ответа HTTP - 401. Тогда все в порядке, но похоже, что данные никогда не сохраняются в базе данных.


person James Wagstaff    schedule 12.03.2020    source источник
comment
У вас @Transactional на @Test?   -  person Nonika    schedule 12.03.2020
comment
Пожалуйста, опубликуйте полную версию Testcase   -  person Nonika    schedule 12.03.2020
comment
Я обновил свой вопрос, чтобы включить более подробную информацию о фабрике   -  person James Wagstaff    schedule 12.03.2020


Ответы (1)


Я думаю, у вас есть тестовый пример с @Transactional вверху, это означает, что эта транзакция никогда не будет совершена, поскольку это @Test.

Поэтому, когда вы делаете http вызов restTemplate, транзакция не фиксируется, и изменения не будут видны для /logIn конечной точки. (это обычный HTTP-запрос и не ограничен @Test @Transactional)

Вы можете использовать mockmvc вместо RestTemplate для вызова конечной точки входа и подтверждения результатов. Оба mockmvc будут связаны одной и той же транзакцией, и изменения будут видны.

ИЗМЕНИТЬ

В случае, если / login не является частью этой службы, вы должны использовать репозиторий пользователей, чтобы в какой-то момент получить пароль от db. repo.findUserByFirstName может быть, и проверьте, что вам нужно. Поскольку этот вызов будет в той же транзакции, результат также будет действительным.

person Nonika    schedule 12.03.2020
comment
Большое спасибо за ваш ответ, он помог понять, как MockMvc работает внутри, я должен был объяснить, что я использую RestTemplate, потому что конечная точка входа в систему является частью шлюза, а не службой пользователей, которая контролирует информацию о пользователях. - person James Wagstaff; 12.03.2020
comment
из текущей транзакции вы можете свободно выбрать что-нибудь из базы данных и убедиться, что нет необходимости вызывать внешнюю службу. - person Nonika; 12.03.2020
comment
Также тест должен быть автономным, не должно быть обращений к внешним сервисам / базам данных. Вы должны протестировать свой собственный код. Рекомендуется использовать встроенную базу данных для тестирования и имитировать все внешние вызовы соответствующими способами. - person Nonika; 12.03.2020