java.lang.AssertionError: Status expected:<400> but was:<200> Expected :400 Actual :200

So, I have been testing a springboot MVC today, and when I run a test, I can not get the error to activate through using the test:


  @Test
    void post_A_User_passwords_do_notMatch() throws  Exception {

         User newUser = new User("TestName", "[email protected]", "NOT_THE_SAME","password123", true);

        // * Building the request
        RequestBuilder postAUser = MockMvcRequestBuilders.post("/users")
                .contentType(MediaType.APPLICATION_JSON)
                .header("authorization", "Bearer " + accessToken)
                .content(objectMapper.writeValueAsString(newUser));

        // * Sending the request
        ResultActions posting = mockMvc.perform(postAUser);

        // * Analysing the result
        MvcResult mvcResult = posting
                .andExpect(status().isBadRequest())
                .andReturn();


    }

The error never gets hit, even though I pass data through the mock post in JSON form. All I get is:

java.lang.AssertionError: Status expected:<400> but was:<200> Expected :400 Actual :200

So, I changed the actual original entity so that the instance fields had matching passwords and then not matching passwords, and hey presto the error was hit when the entity has non-matching passwords in the instance fields. So, this led me to the conclusion that when the mapping is called, a blank user entity template is passed into the service (Well one that is the same as it is set in the user model), then it runs through the business service, then the JSON data is saved into the repo after this occurs, then a response is sent in JSON that can be accessed.

Ideally, I want to be able to hit the error through the JSON Data when, such that if two passwords do not match on the incoming data then the error is activated, through the user service.

So, I have questions, regarding the test, trying to hit the error and the output:

  1. whether I have made the correct conclusion about the entity getting passed in without the JSON data.
  2. if any data gets saved in the as JAVA in JAVA end (IntelliJ) and it is not just persisted in the database and returned as a JSON response.
  3. How would one hit the error?

The entity and then the relevant parts of the user controller and user service are posted below. I am just extending a CRUD repository for the user repo. I have set the spring security to permit all paths.

package bookapp.backend.model;

import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Getter;
import lombok.Setter;

import javax.persistence.*;
import java.util.List;

@Entity
@Table(name = "users")
@Getter @Setter
public class User {
    @Id // Change to UUID later after testing
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column
    private Integer id;

    @Column
    @JsonProperty("userName")
    private String userName;

    @Column
    private String email;

    @Column
    @JsonProperty(access = JsonProperty.Access.WRITE_ONLY, value = "password")
    private String password = "";

    @Transient
    @JsonProperty(access = JsonProperty.Access.WRITE_ONLY)
    @Column
    private String passwordConfirmation = "";

    @Column
    private Boolean isAdmin;

    // Relationships

    // reviews
    @OneToMany
    private List<Review>reviewList;

    // Not sure how the relationship between myLibrary and myReadBooks with books will work
    // Leaving this as it is for now, but might have to change annotations etc

    @OneToMany
    private List<Book> myLibrary;

    @OneToMany
    private List<Book> myReadBooks;

    // * Constructors Added for Testing
    public User() {
    }

    public User(String userName, String email, String password, String passwordConfirmation, Boolean isAdmin) {
        this.userName = userName;
        this.email = email;
        this.password = password;
        this.passwordConfirmation = passwordConfirmation;
        this.isAdmin = isAdmin;
    }

    // * ToString Added for Testing
    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", userName='" + userName + '\'' +
                ", email='" + email + '\'' +
                ", password='" + password + '\'' +
                ", passwordConfirmation='" + passwordConfirmation + '\'' +
                ", isAdmin=" + isAdmin +
                '}';
    }
}

This controller method in the controller

 // ! Create a new user
    @PostMapping("/users")
    public User postUser(@RequestBody @Valid User user) { return userService.createUser(user); }


It also has this method in the service:

    // ! This method creates a new user in the UserRepo
    public User createUser(User user) {
        // ! Check if password matches the passwordConfirmation

        if (!user.getPassword().equals(user.getPasswordConfirmation())) {
            throw new ResponseStatusException(HttpStatus.NOT_FOUND, "Password does not match password confirmation");
        }

        // ! Check if the user already exists in the UserRepo
//        Optional<User> existingUser = userRepo.findByUsername(user.getUserName());
//        if (existingUser.isPresent()) {
//            throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "A user with that username already exists");
//        }

        // ! Encrypt password with bCrypt
        String encodedPassword = bCryptPasswordEncoder.encode(user.getPassword());
        user.setPassword(encodedPassword);

        return userRepo.save(user);
    }

Upvotes: 0

Views: 2150

Answers (1)

@Test
void post_A_User_ErrorCheck2() throws  Exception {

    objectMapper.disable(MapperFeature.USE_ANNOTATIONS);

    User newUser = new User("testName", "[email protected]", "password$DO_NOT_MATCH123","password$123", true);

    // *  Building the request
    RequestBuilder postAnUser = MockMvcRequestBuilders
            .post("/users")
            .contentType(MediaType.APPLICATION_JSON)
            .header("authorization", "Bearer " + accessToken)
            .content(objectMapper.writeValueAsString(newUser));

    // * Performing the Request
    ResultActions postingAnUser = mockMvc.perform(postAnUser);

    // * Analysing the results
    MvcResult testResult = postingAnUser
            .andExpect(status().isNotFound())
            .andReturn();
}

So, it turned out that the JSON ignore property @JsonProperty(access = JsonProperty.Access.WRITE_ONLY, value = "password") that annotates the entity prevents the serialization of the data. This occurs on the object mapper object that is present in the test. The @JsonProperty(access = JsonProperty.Access.WRITE_ONLY) is needed to prevent the passwords from getting returned in the response, but in this case, we use objectMapper.disable(MapperFeature.USE_ANNOTATIONS), to allow them to be written. Furthermore, the test in the @Test has an error isBadrequest() that does not match the HttpStatus.NOT_FOUND error in the user service.

Upvotes: 1

Related Questions