Zob*_*san 63 java unit-testing spring-mvc jsonpath mockmvc
我一直在为一个简单的spring Web应用程序编写一些简单的单元测试例程.当我在资源的getter方法上添加@JsonIgnore注释时,生成的json对象不包含相应的json元素.因此,当我的单元测试例程尝试测试它是否为null(这是我的情况的预期行为,我不希望密码在json对象中可用)时,测试例程会遇到异常:
java.lang.AssertionError:JSON路径没有值:$ .password,exception:路径没有结果:$ ['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());
}
Run Code Online (Sandbox Code Playgroud)
我也尝试过使用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);
}
}
Run Code Online (Sandbox Code Playgroud)
我使用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;
}
}
Run Code Online (Sandbox Code Playgroud)
我理解为什么这会产生异常,同样在某种程度上,测试成功无法找到密码字段.但我想要做的是,运行此测试以确保该字段不存在,或者如果存在,则它包含空值.我怎样才能做到这一点?
堆栈溢出中有一个类似的帖子: 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>
Run Code Online (Sandbox Code Playgroud)
提前致谢.
[编辑]更准确地说,你必须为一个实体编写测试,你知道某些字段需要为空或空或者甚至不存在,并且你实际上并没有通过代码来查看如果在属性顶部添加了JsonIgnore.并且您希望测试通过,我该怎么做.
请随时告诉我这根本不实用,但仍然很高兴知道.
[编辑]以上测试成功使用以下较旧的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>
Run Code Online (Sandbox Code Playgroud)
[编辑]在阅读了spring的json路径匹配器的文档后,发现了一个与最新版本的jayway.jasonpath一起使用的quickfix.
.andExpect(jsonPath("$.password").doesNotExist())
Run Code Online (Sandbox Code Playgroud)
小智 129
我对新版本遇到了同样的问题.在我看来,doesNotExist()函数将验证该键不在结果中:
.andExpect(jsonPath("$.password").doesNotExist())
Run Code Online (Sandbox Code Playgroud)
Wim*_*uwe 15
存在但具有null价值的财产和根本不存在的财产之间是有区别的。
如果测试仅在存在非null值时失败,请使用:
.andExpect(jsonPath("password").doesNotExist())
Run Code Online (Sandbox Code Playgroud)
如果该属性一出现测试就失败,即使有一个null值,请使用:
.andExpect(jsonPath("password").doesNotHaveJsonPath())
Run Code Online (Sandbox Code Playgroud)
@JsonIgnore 的行为符合预期,不会在 json 输出中生成密码,因此您如何期望测试从输出中明确排除的内容?
该行:
.andExpect(jsonPath("$.property", is("some value")));
Run Code Online (Sandbox Code Playgroud)
甚至测试该属性是否为空:
.andExpect(jsonPath("$.property").value(IsNull.nullValue()));
Run Code Online (Sandbox Code Playgroud)
对应一个json:
{
...
"property": "some value",
...
}
Run Code Online (Sandbox Code Playgroud)
其中重要的部分是左边,那就是“属性”的存在:
相反,@JsonIgnore 根本不会在输出中产生属性,因此您不能期望它不在测试中或在生产输出中。如果您不希望输出中出现该属性,也可以,但您不能期望在测试中出现该属性。如果您希望输出为空(在产品和测试中),您需要在中间创建一个静态 Mapper 方法,该方法不将属性值传递给 json 对象:
Mapper.mapPersonToRest(User user) {//exclude the password}
Run Code Online (Sandbox Code Playgroud)
然后你的方法是:
@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);
}
}
Run Code Online (Sandbox Code Playgroud)
此时,如果您期望 Mapper.mapPersonToRest 返回密码为空的用户,则可以对此方法编写正常的单元测试。
PS 当然密码在数据库上是加密的,对吧?;)
| 归档时间: |
|
| 查看次数: |
50125 次 |
| 最近记录: |