UFO ET IT

JSON 경로에 특정 요소가 포함되어 있지 않거나 요소가 존재하는지 여부를 테스트하는 방법은 null입니까?

ufoet 2020. 12. 29. 07:35
반응형

JSON 경로에 특정 요소가 포함되어 있지 않거나 요소가 존재하는지 여부를 테스트하는 방법은 null입니까?


저는 간단한 봄 웹 애플리케이션을위한 간단한 단위 테스트 루틴을 작성했습니다. 리소스의 getter 메서드에 @JsonIgnore 주석을 추가하면 결과 json 객체에 해당 json 요소가 포함되지 않습니다. 따라서 내 단위 테스트 루틴이 이것이 null인지 테스트하려고 할 때 (제 경우에 예상되는 동작이며 json 객체에서 비밀번호를 사용할 수 없기를 원합니다) 테스트 루틴이 예외로 실행됩니다.

java.lang.AssertionError : JSON 경로 값 없음 : $ .password, 예외 : 경로에 대한 결과 없음 : $ [ 'password']

is (nullValue ()) 메서드로 'password'필드를 테스트하여 작성한 단위 테스트 메서드입니다.

@Test
public void getUserThatExists() throws Exception {
    User user = new User();
    user.setId(1L);
    user.setUsername("zobayer");
    user.setPassword("123456");

    when(userService.getUserById(1L)).thenReturn(user);

    mockMvc.perform(get("/users/1"))
            .andExpect(jsonPath("$.username", is(user.getUsername())))
            .andExpect(jsonPath("$.password", is(nullValue())))
            .andExpect(jsonPath("$.links[*].href", hasItem(endsWith("/users/1"))))
            .andExpect(status().isOk())
            .andDo(print());
}

또한 경로가 존재하지 않는다는 유사한 예외가 발생하는 jsonPath (). exists ()로 시도했습니다. 전체 상황을 더 쉽게 읽을 수 있도록 더 많은 코드를 공유하고 있습니다.

테스트중인 컨트롤러 방법은 다음과 같습니다.

@RequestMapping(value="/users/{userId}", method= RequestMethod.GET)
public ResponseEntity<UserResource> getUser(@PathVariable Long userId) {
    logger.info("Request arrived for getUser() with params {}", userId);
    User user = userService.getUserById(userId);
    if(user != null) {
        UserResource userResource = new UserResourceAsm().toResource(user);
        return new ResponseEntity<>(userResource, HttpStatus.OK);
    } else {
        return new ResponseEntity<>(HttpStatus.NOT_FOUND);
    }
}

엔티티를 리소스 객체로 변환하기 위해 spring hateos 리소스 어셈블러를 사용하고 있으며 이것이 내 리소스 클래스입니다.

public class UserResource extends ResourceSupport {
    private Long userId;
    private String username;
    private String password;

    public Long getUserId() {
        return userId;
    }

    public void setUserId(Long userId) {
        this.userId = userId;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    @JsonIgnore
    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }
}

나는 이것이 예외가 발생하는 이유를 이해합니다. 또한 테스트가 성공하여 암호 필드를 찾을 수 없습니다. 하지만 내가 원하는 것은이 테스트를 실행하여 필드가 없는지 확인하거나 필드가있는 경우 null 값을 포함하는지 확인하는 것입니다. 이것을 어떻게 달성 할 수 있습니까?

스택 오버플로에 비슷한 게시물이 있습니다. Hamcrest with MockMvc : 키가 있는지 확인하지만 값이 null 일 수 있음

제 경우에는 필드가 존재하지 않을 수도 있습니다.

기록을 위해 다음은 내가 사용중인 테스트 패키지 버전입니다.

    <dependency>
        <groupId>com.fasterxml.jackson.core</groupId>
        <artifactId>jackson-core</artifactId>
        <version>2.6.1</version>
    </dependency>
    <dependency>
        <groupId>com.fasterxml.jackson.core</groupId>
        <artifactId>jackson-annotations</artifactId>
        <version>2.6.1</version>
    </dependency>
    <dependency>
        <groupId>com.fasterxml.jackson.core</groupId>
        <artifactId>jackson-databind</artifactId>
        <version>2.6.1</version>
    </dependency>
    <dependency>
        <groupId>com.jayway.jsonpath</groupId>
        <artifactId>json-path</artifactId>
        <version>2.0.0</version>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>com.jayway.jsonpath</groupId>
        <artifactId>json-path-assert</artifactId>
        <version>2.0.0</version>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.12</version>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>org.mockito</groupId>
        <artifactId>mockito-all</artifactId>
        <version>1.10.19</version>
        <scope>test</scope>
    </dependency>

미리 감사드립니다.

[편집] 좀 더 정확하게 말하자면, 일부 필드가 null이거나 비어 있거나 존재하지 않아야한다는 것을 알고있는 엔티티에 대한 테스트를 작성해야하며 실제로 코드를 확인하지 않습니다. 속성 위에 추가 된 JsonIgnore가있는 경우. 그리고 당신은 당신의 테스트가 통과되기를 원합니다. 어떻게 할 수 있습니까?

이것은 전혀 실용적이지 않지만 여전히 알면 좋을 것입니다.

[편집] 위의 테스트는 다음과 같은 이전 json-path 종속성으로 성공합니다.

    <dependency>
        <groupId>com.jayway.jsonpath</groupId>
        <artifactId>json-path</artifactId>
        <version>0.9.1</version>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>com.jayway.jsonpath</groupId>
        <artifactId>json-path-assert</artifactId>
        <version>0.9.1</version>
        <scope>test</scope>
    </dependency>

[편집] spring의 json path matcher 문서를 읽은 후 jayway.jasonpath의 최신 버전에서 작동하는 빠른 수정을 찾았습니다.

.andExpect(jsonPath("$.password").doesNotExist())

새 버전에서도 같은 문제가 발생했습니다. doesNotExist () 함수가 키가 결과에 없는지 확인하는 것으로 보입니다.

.andExpect(jsonPath("$.password").doesNotExist())

@JsonIgnore is behaving as expected, not producing the password in the json output, so how could you expect to test something that you are explicitly excluding from the output?

The line:

.andExpect(jsonPath("$.property", is("some value")));

or even a test that the property is null:

.andExpect(jsonPath("$.property").value(IsNull.nullValue()));

correspond to a json like:

{
...
"property": "some value",
...
}

where the important part is the left side, that is the existence of "property":

Instead, @JsonIgnore is not producing the porperty in the output at all, so you can't expect it not in the test nor in the production output. If you don't want the property in the output, it's fine, but you can't expect it in test. If you want it empty in output (both in prod and test) you want to create a static Mapper method in the middle that is not passing the value of the property to the json object:

Mapper.mapPersonToRest(User user) {//exclude the password}

and then your method would be:

@RequestMapping(value="/users/{userId}", method= RequestMethod.GET)
public ResponseEntity<UserResource> getUser(@PathVariable Long userId) {
    logger.info("Request arrived for getUser() with params {}", userId);
    User user = Mapper.mapPersonToRest(userService.getUserById(userId));
    if(user != null) {
        UserResource userResource = new UserResourceAsm().toResource(user);
        return new ResponseEntity<>(userResource, HttpStatus.OK);
    } else {
        return new ResponseEntity<>(HttpStatus.NOT_FOUND);
    }
}

At this point, if your expectations are for Mapper.mapPersonToRest to return a user with a null password, you can write a normal Unit test on this method.

P.S. Of course the password is crypted on the DB, right? ;)

ReferenceURL : https://stackoverflow.com/questions/32397690/how-to-test-if-json-path-does-not-include-a-specific-element-or-if-the-element

반응형