Подтвердить что ты не робот

Как проверить, не содержит ли JSON-путь какой-либо конкретный элемент, или если элемент присутствует, он равен нулю?

Я написал несколько простых процедур тестирования модулей для простого веб-приложения spring. Когда я добавляю аннотацию @JsonIgnore к методу getter ресурса, результирующий объект json не включает соответствующий json-элемент. Поэтому, когда моя процедура unit test пытается проверить, является ли это нулевым (что является ожидаемым поведением для моего случая, я не хочу, чтобы пароль был доступен в json-объекте), тестовая процедура запускается в исключение:

java.lang.AssertionError: Нет значения для пути JSON: $.password, exception: Нет результатов для пути: $['password']

Это метод unit test, который я написал, проверяя поле "пароль" с методом (nullValue()):

@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 revos для преобразования объекта в объекты ресурса, и это мой класс ресурсов:

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;
    }
}

Я понимаю, почему это вызывает исключение, также в некотором смысле, тест успешный, что он не смог найти поле пароля. Но то, что я хочу сделать, это запустить этот тест, чтобы убедиться, что это поле отсутствует, или если оно присутствует, оно содержит нулевое значение. Как я могу достичь этого?

В переполнении стека есть аналогичная запись: Hamcrest с MockMvc: проверьте, что ключ существует, но значение может быть нулевым

В моем случае поле может быть и не существующим.

Для записи это версии тестовых пакетов, которые я использую:

    <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>

Спасибо заранее.

[EDIT] Чтобы быть более точным, скажем, вам нужно написать тест для объекта, в котором вы знаете, что некоторые из полей должны быть пустыми или пустыми или их даже не существует, и вы фактически не просматриваете код, чтобы увидеть, есть ли JsonIgnore добавил к собственности. И вы хотите, чтобы ваши тесты проходили, как я могу это сделать.

Пожалуйста, не стесняйтесь сказать мне, что это совсем не практично, но все равно было бы хорошо знать.

[EDIT] Вышеупомянутый тест преуспевает со следующими более старыми зависимостями 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>

[EDIT] Найден quickfix, который работает с последней версией jayway.jasonpath после прочтения документации spring json path matcher.

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

Ответ 1

У меня была такая же проблема с новой версией. Мне кажется, что функция doesNotExist() проверяет, что ключ не находится в результате:

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

Ответ 2

@JsonIgnore ведет себя так, как ожидалось, не создавая пароль в json-выходе, так как вы можете ожидать, чтобы проверить что-то, что вы явно исключаете из вывода?

Строка:

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

или даже тест, что свойство имеет значение null:

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

соответствуют json like:

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

где важная часть - левая сторона, то есть существование "свойства":

Вместо этого @JsonIgnore вообще не производит произвольную обработку на выходе, поэтому вы не можете ожидать этого не в тесте, а в производственном выпуске. Если вы не хотите, чтобы свойство выводилось, это нормально, но вы не можете ожидать его в тесте. Если вы хотите, чтобы он был пустым на выходе (как в prod, так и в тесте), вы хотите создать статический метод Mapper в середине, который не передает значение свойства объекту json:

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

а затем ваш метод будет выглядеть следующим образом:

@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);
    }
}

В этом случае, если ваши ожидания в Mapper.mapPersonToRest возвращают пользователя с нулевым паролем, вы можете записать обычный Unit test этот метод.

P.S. Конечно, пароль зашифрован в БД, не так ли?;)