Spring注册接口哈希密码测试难题:DTO隐藏密码致无法验证
解决Spring注册用户时密码哈希的测试问题
你的UserResponseDTO里给password字段加了@JsonProperty(access = JsonProperty.Access.WRITE_ONLY),这个注解的作用是序列化时不输出该字段,反序列化时也不会解析该字段。所以你从响应JSON反序列化成UserResponseDTO时,password必然是null——这就是辅助方法里拿不到加密密码的核心原因。
而你的需求是:响应不能返回密码,但要验证密码确实被正确哈希存储了。正确的做法是绕过响应体,直接从数据源(比如数据库)获取用户的加密密码,具体步骤如下:
1. 注入用户数据访问组件到测试类
如果用JPA,就注入对应的UserRepository;如果是自定义用户服务,就注入UserService。示例代码:
@Autowired private UserRepository userRepository; @Autowired private PasswordEncoder passwordEncoder;
2. 修改测试逻辑,从数据库验证密码哈希
注册请求成功后,通过用户名查询数据库里的用户实体,用passwordEncoder验证原始密码和存储的哈希是否匹配。同时要加断言确保响应体里确实没有密码字段:
修改后的测试代码示例:
@Test @DisplayName("Create a user") @DirtiesContext public void createUserTest() { String rawPassword = getRandomPassword(); String username = "john"; // 发起注册请求 var postResponse = postRequest("/api/auth/signup", createUserRequest(username, rawPassword)); assertThat(postResponse.getStatusCode()).isEqualTo(HttpStatus.CREATED); // 1. 验证响应体中不包含password字段 String actualJson = postResponse.getBody(); JsonPath jsonPath = JsonPath.compile("$.password"); assertThatThrownBy(() -> jsonPath.read(actualJson)) .withFailMessage("响应体不应包含password字段") .isInstanceOf(PathNotFoundException.class); // 2. 从数据库查询用户,验证密码哈希正确性 User savedUser = userRepository.findByUsername(username) .orElseThrow(() -> new AssertionError("注册的用户未找到")); assertThat(passwordEncoder.matches(rawPassword, savedUser.getPassword())) .withFailMessage("密码哈希与原始密码不匹配") .isTrue(); // 3. 验证响应体的其他字段符合预期 UserResponseDTO actual = toModel(actualJson, UserResponseDTO.class); UserResponseDTO expected = createUserResponse(username, Roles.USER); assertThat(actual).isEqualTo(expected); assertThat(actualJson).isEqualTo(toJsonString(expected)); }
3. 为什么不能从响应拿密码?
你的业务规则明确要求响应不能返回密码,所以响应JSON里根本不存在这个字段,自然没法从这里获取。测试要贴合实际业务:既要保证响应不泄露密码,又要保证密码被正确处理存储,直接查询数据源是最直接有效的方式。
内容的提问来源于stack exchange,提问作者IceMajor
相关产品推荐
相关产品推荐

