Тестирование SpringBoot REST API MockMvc не привело к успешному созданию пользователей, несмотря на ту же функциональность, работающую в проекте React

#java #reactjs #spring #spring-boot #mockmvc

#Ява #реагирует на #весна #пружинный ботинок #mockmvc

Вопрос:

У меня есть метод в моем пользовательском контроллере моего API SpringBoot REST, который регистрирует пользователя, анализируя объект json в строку, а затем создавая новый объект пользователя и сохраняя его в базе данных с помощью репозитория JPA.

В моем отдельном интерфейсном проекте CORS React, когда пользователь переходит на домашнюю страницу, в API отправляется запрос POST, который успешно регистрирует пользователя (в качестве теста) с полезной нагрузкой JSON:

 {username: "mitton", password: "JohnSmith72-"}  

Это работает нормально, и когда я захожу в проект React /home, я вижу, что пользователь был успешно создан и сохранен, поэтому я знаю, что эта функция работает.

Я пытаюсь протестировать этот метод контроллера с помощью JUnit и MockMvc, но когда я пытаюсь сделать тот же запрос POST с помощью MockMvc, возвращается 200, но пользователь не создается.

UserControllerTest.java

 @RunWith(SpringRunner.class) @SpringBootTest @AutoConfigureMockMvc public class UserControllerTest {   @Autowired MockMvc mvc;  @MockBean  UserService userService;   @Test public void addUserTest() throws Exception {   TestUser testUser = new TestUser("timcard", "TimCard72-");   mvc.perform(post("http://localhost:8080/users/signup")  .contentType(MediaType.APPLICATION_JSON)  .accept(MediaType.APPLICATION_JSON)  .content(asJsonString(testUser)))  .andExpect(status().isOk());   Optionallt;Usergt; user = userService.getUser(1L);  Optionallt;Usergt; justInCaseUser = userService.getUser(1L);  System.out.println(user.toString());  System.out.println(justInCaseUser.toString());  }   public static String asJsonString(final Object obj) {  try {  final ObjectMapper mapper = new ObjectMapper();  final String jsonContent = mapper.writeValueAsString(obj);  System.out.println(jsonContent);  return jsonContent;  } catch (Exception e) {  throw new RuntimeException(e);  }  } }  

Ответ:

Запрос / ответ MockMvc / что печатается:

 {"username":"timcard","password":"TimCard72-"} Optional.empty Optional.empty  

Full successful react request:

 componentDidMount() {  const payload2 = {  "username": "mitton",  "password": "JohnSmith72-"  }  fetch(SIGNUP_URL, {  method: 'POST',  headers: {  "Accept": "application/json",  "Content-Type": "application/json"  },  body: JSON.stringify(payload2)  })  .then(response =gt; response.json())  .then((data) =gt; {  console.log(data);  }); }  

In request browser: General:

 Request URL: http://localhost:8080/users/signup Request Method: POST Status Code: 200 Remote Address: [::1]:8080 Referrer Policy: strict-origin-when-cross-origin  

Headers:

 Accept: application/json  Accept-Encoding: gzip, deflate, br  Accept-Language: en-US,en;q=0.9  Connection: keep-alive  Content-Length: 47  Content-Type: application/json  Host: localhost:8080  Origin: http://localhost:3000  Referer: http://localhost:3000/  sec-ch-ua: " Not A;Brand";v="99", "Chromium";v="96", "Microsoft Edge";v="96"  sec-ch-ua-mobile: ?0  sec-ch-ua-platform: "Windows"  Sec-Fetch-Dest: empty  Sec-Fetch-Mode: cors  Sec-Fetch-Site: same-site  User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.55 Safari/537.36 Edg/96.0.1054.41  

Payload:

 {username: "mitton", password: "JohnSmith72-"}  

The reason I created a TestUser class to use as a temporary object class to map the JSON payload in the test as opposed to using the User entity class is because when I create the User entity object, it automatically generates the ID field, and this would cause issues as the controller logic is supposed to only work with a json string as above with a username, password, not also a generated ID.

TestUser:

 @Getter @Setter @AllArgsConstructor @NoArgsConstructor public class TestUser {  @Column(name = "username", unique = true)  private String username;   @Column(name = "password")  private String password; }  

UserController:

 @RestController @RequestMapping(value = "/users") @CrossOrigin(origins = {"http://localhost:3000", "http://localhost:8080"}) public class UserController {   final  UserService userService;    public UserController(UserService userService) {  this.userService = userService; }   @PostMapping("/signup")  public void signUp(@RequestBody User user) {  userService.signUpUser(user);  } }  

Обслуживание пользователей:

 public void signUpUser(User user) {  user.setPassword(bCryptPasswordEncoder.encode(user.getPassword()));  userRepository.save(user); }  

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

 @Entity(name = "User") @Table(name = "user") @Getter @Setter @AllArgsConstructor @NoArgsConstructor public class User implements Serializable {   @Id  @GeneratedValue(strategy = GenerationType.IDENTITY)  private long id;   @Column(name = "username", unique = true)  private String username;   @Column(name = "password")   private String password;   public User(String username, String password) {   this.username = username;  this.password = password;   } }  

Комментарии:

1. И почему это должно быть так? Вы издеваетесь над службой… ПОЭТОМУ, что бы ни делала служба, она этого не делает, поскольку экземпляр заменяется издевательским экземпляром.

2. @M. Deinum О, так есть ли какой-нибудь способ сделать это, не создавая издевательский сервис или что-то в этом роде? Я действительно просто хотел проверить это так, как если бы проект React отправлял запросы в API. Спасибо.

3. Не используйте @MockBean просто используйте @Autowired … Это не более сложно, чем это. Или используйте издевательский экземпляр и просто проверьте, вызывается ли метод сохранения служб, вместо того, чтобы пытаться узнать, сохранен ли пользователь в базе данных.

4. @M. Deinum Спасибо за вашу помощь, работает отлично!

5. Ну, вы могли бы их использовать, но, вообще говоря, проводить тесты, зависящие друг от друга, — плохая идея. Если ваш заказ на тестирование изменится или вы добавите новые тесты, все изменится, и вы внезапно столкнетесь с трудностями в отслеживании сбоев тестирования.