2015-09-04 5 views
33

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

java.lang.AssertionError: No value for JSON path: $.password, exception: No results for path: $['password']

Это метод модульного тестирования я написал, тестирование поля «пароль» с есть() 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("https://stackoverflow.com/users/1")) 
      .andExpect(jsonPath("$.username", is(user.getUsername()))) 
      .andExpect(jsonPath("$.password", is(nullValue()))) 
      .andExpect(jsonPath("$.links[*].href", hasItem(endsWith("https://stackoverflow.com/users/1")))) 
      .andExpect(status().isOk()) 
      .andDo(print()); 
} 

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

Метод контроллера Я тестирование выглядит примерно так:

@RequestMapping(value="https://stackoverflow.com/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); 
    } 
} 

Я использую пружинный 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; 
    } 
} 

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

Существует аналогичный пост в переполнение стека: Hamcrest with MockMvc: check that key exists but value may be 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> 

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

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

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

[EDIT] выше тест успешно со следующими старыми зависимостями JSON-путем:

<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 после прочтения документации весны JSON путь.

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

Спасибо за ваш последний «ИЗОБРАЖЕНИЕ». '.DoesNotExist()' был тем, что я ищу. – James

ответ

65

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

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

, вот что я сделал, посмотрите на последнюю строку моего вопроса. [вопрос в последний раз отредактировал \t 4 сен '15 в 14:55] –

+1

, если вы используете AssertJ (например,в приложении Spring Boot), это способ проверить его 'assertThat (this.json.write (entity)). doesNotHaveJsonPathValue (" @. keyl ");' –

2

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

Линия:

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

или даже тест, что свойство является пустым:

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

соответствуют JSON как:

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

, где важной частью является левая сторона, то есть существование «собственности»:

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

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

и тогда ваш метод был бы:

@RequestMapping(value="https://stackoverflow.com/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 вернуть пользователь с пустым паролем, вы можете написать нормальный тест блока по этому методу.

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

+0

Да JsonIgnore выполняет как можно раньше. Итак, какова была бы лучшая практика тестирования объектов с JsonIgnore над некоторыми полями. Предположим, что вы хотите написать тест, вы знаете, какие поля должны быть пустыми или нулевыми (или даже не должны существовать), но вы не собираетесь открывать исходный код и читать, если на них есть аннотация JsonIgnore. и, очевидно, вы хотите, чтобы ваш тест прошел, а не с исключением. О, конечно, пароль хэшируется. Не то чтобы это важно, просто тестовый проект. –

+0

Что вы хотите сделать, так это то, что объект UserResource не возвращает пароль, верно? Допустим, у вас есть новый UserResourceAsm(). ToResource (пользователь), возвращающий пользователя, правильно? В этом случае вы должны протестировать не на уровне SpringMVC, а просто выполнить обычный модульный тест, который проверяет user.getPassword() значение null. Надеюсь, это прояснится! – Paolof76

+0

Я добавил пример, который поможет вам понять, что я имею в виду. Позвольте мне посмотреть, есть ли у вас больше сомнений – Paolof76