Junit5:WebMvcTest returns 404。可能是因为我没有模拟底层方法?
Junit5: WebMvcTest returns 404. Probably because I'm not mocking underlyng method?
序言:我正在学习 Java、Spring 引导和总体......使用 Java/Spring 引导的 TDD。
使用的版本:
- Spring 启动 2.6.3
- Java 17
- Junit5
这是我的控制器:
@RestController
@RequestMapping("/api/v1/login")
public class LoginController {
@Autowired
private JwtAuthentication jwtAuthentication;
@Autowired
private JwtTokenUtil jwtTokenUtil;
@Autowired
private JwtUserDetailService jwtUserDetailService;
@PostMapping
public ResponseEntity<?> createAuthenticationToken(@RequestBody UserEntity userEntity) throws Exception {
jwtAuthentication.authenticate(userEntity.getUsername(), userEntity.getPassword());
final UserDetails userDetails = jwtUserDetailService.loadUserByUsername(userEntity.getUsername());
final String token = jwtTokenUtil.generateToken(userDetails);
return ResponseEntity.ok(new JwtResponse(token));
}
}
相关autowired
是JwtAuthentication
:
@Component
public class JwtAuthentication {
@Autowired
private AuthenticationManager authenticationManager;
private static final long serialVersionUID = -20220210203900L;
public void authenticate(String username, String password) throws BadCredentialsException {
try {
authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(username, password));
} catch (BadCredentialsException e) {
throw new BadCredentialsException("INVALID_CREDENTIALS", e);
}
}
}
我为 JwtAuthentication
本身编写的测试没有问题,现在我需要测试控制器。
这是我的测试:
@ExtendWith(SpringExtension.class)
@WebMvcTest(LoginControllerTest.class)
class LoginControllerTest {
@Autowired
private MockMvc mvc;
@Autowired
private ObjectMapper objectMapper;
@MockBean
private JwtAuthentication jwtAuthentication;
@Test
void testCanLogin() throws Exception {
UserEntity userEntity = new UserEntity();
userEntity.setUsername("username");
userEntity.setPassword("password");
mvc.perform(post("/api/v1/login/").contentType(MediaType.APPLICATION_JSON)
.content(objectMapper.writeValueAsBytes(userEntity))).andExpect(status().isOk());
}
}
但我得到的是 404 而不是 200。
我读到原因是缺少模拟底层方法。实际上,控制器上的这些测试不会启动整个配置(等等)。在 S.O..
上找不到答案 atm
所以,我认为解决方案需要在测试中添加一个“简单的”when
:
@Test
void testCanLogin() throws Exception {
UserEntity userEntity = new UserEntity();
userEntity.setUsername("username");
userEntity.setPassword("password");
// I think I need some code here:
// pseudocode when(jwtAuthentication.authenticate("username", "password").then .... I DON'T KNOW HERE!
mvc.perform(post("/api/v1/login/").contentType(MediaType.APPLICATION_JSON)
.content(objectMapper.writeValueAsBytes(userEntity))).andExpect(status().isOk());
}
404 是因为没有控制器来处理请求。
因为您在@WebMvcTest
中指定了错误的控制器,导致您要测试的控制器没有包含在spring容器中。所以更改为以下内容应该可以解决问题:
@WebMvcTest(LoginController.class)
class LoginControllerTest {
@MockBean
private JwtAuthentication jwtAuthentication;
@MockBean
private JwtTokenUtil jwtTokenUtil;
@MockBean
private JwtUserDetailService jwtUserDetailService;
}
还要注意以下几点:
- 我删除了
@ExtendWith(SpringExtension.class)
,因为 @WebMvcTest
已经包含了它
@WebMvcTest
只会启用与 web 层相关的 bean(参见 this),而 JwtTokenUtil
和 JwtUserDetailService
不属于它。所以你必须使用 @MockBean
来模拟它们。
序言:我正在学习 Java、Spring 引导和总体......使用 Java/Spring 引导的 TDD。
使用的版本:
- Spring 启动 2.6.3
- Java 17
- Junit5
这是我的控制器:
@RestController
@RequestMapping("/api/v1/login")
public class LoginController {
@Autowired
private JwtAuthentication jwtAuthentication;
@Autowired
private JwtTokenUtil jwtTokenUtil;
@Autowired
private JwtUserDetailService jwtUserDetailService;
@PostMapping
public ResponseEntity<?> createAuthenticationToken(@RequestBody UserEntity userEntity) throws Exception {
jwtAuthentication.authenticate(userEntity.getUsername(), userEntity.getPassword());
final UserDetails userDetails = jwtUserDetailService.loadUserByUsername(userEntity.getUsername());
final String token = jwtTokenUtil.generateToken(userDetails);
return ResponseEntity.ok(new JwtResponse(token));
}
}
相关autowired
是JwtAuthentication
:
@Component
public class JwtAuthentication {
@Autowired
private AuthenticationManager authenticationManager;
private static final long serialVersionUID = -20220210203900L;
public void authenticate(String username, String password) throws BadCredentialsException {
try {
authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(username, password));
} catch (BadCredentialsException e) {
throw new BadCredentialsException("INVALID_CREDENTIALS", e);
}
}
}
我为 JwtAuthentication
本身编写的测试没有问题,现在我需要测试控制器。
这是我的测试:
@ExtendWith(SpringExtension.class)
@WebMvcTest(LoginControllerTest.class)
class LoginControllerTest {
@Autowired
private MockMvc mvc;
@Autowired
private ObjectMapper objectMapper;
@MockBean
private JwtAuthentication jwtAuthentication;
@Test
void testCanLogin() throws Exception {
UserEntity userEntity = new UserEntity();
userEntity.setUsername("username");
userEntity.setPassword("password");
mvc.perform(post("/api/v1/login/").contentType(MediaType.APPLICATION_JSON)
.content(objectMapper.writeValueAsBytes(userEntity))).andExpect(status().isOk());
}
}
但我得到的是 404 而不是 200。
我读到原因是缺少模拟底层方法。实际上,控制器上的这些测试不会启动整个配置(等等)。在 S.O..
上找不到答案 atm所以,我认为解决方案需要在测试中添加一个“简单的”when
:
@Test
void testCanLogin() throws Exception {
UserEntity userEntity = new UserEntity();
userEntity.setUsername("username");
userEntity.setPassword("password");
// I think I need some code here:
// pseudocode when(jwtAuthentication.authenticate("username", "password").then .... I DON'T KNOW HERE!
mvc.perform(post("/api/v1/login/").contentType(MediaType.APPLICATION_JSON)
.content(objectMapper.writeValueAsBytes(userEntity))).andExpect(status().isOk());
}
404 是因为没有控制器来处理请求。
因为您在@WebMvcTest
中指定了错误的控制器,导致您要测试的控制器没有包含在spring容器中。所以更改为以下内容应该可以解决问题:
@WebMvcTest(LoginController.class)
class LoginControllerTest {
@MockBean
private JwtAuthentication jwtAuthentication;
@MockBean
private JwtTokenUtil jwtTokenUtil;
@MockBean
private JwtUserDetailService jwtUserDetailService;
}
还要注意以下几点:
- 我删除了
@ExtendWith(SpringExtension.class)
,因为@WebMvcTest
已经包含了它 @WebMvcTest
只会启用与 web 层相关的 bean(参见 this),而JwtTokenUtil
和JwtUserDetailService
不属于它。所以你必须使用@MockBean
来模拟它们。