如何用 mockito 测试这个类?

Posted

技术标签:

【中文标题】如何用 mockito 测试这个类?【英文标题】:How to test this class with mockito? 【发布时间】:2021-03-06 15:22:15 【问题描述】:

我使用 JWT 令牌实现了 REST API。用户可以注册新帐户,或使用用户名和密码登录。我有一个名为 AuthController 的类。我需要测试两种方法:登录/注册。我想用 Mockito 来测试这个类。

如何模拟身份验证(令牌)?

@RestController
@RequestMapping(value = "/api/auth")
public class AuthController 
    private final AuthenticationManager authenticationManager;
    private final JwtTokenUtils jwtToken;
    private final UserService userService;
    private final UserRepository repository;
    private final PasswordEncoder encoder;
    private final RoleRepository roleRepository;

    @Autowired
    public AuthController(AuthenticationManager authenticationManager, JwtTokenUtils jwtToken, UserService userService, UserRepository repository, PasswordEncoder encoder, RoleRepository roleRepository) 
        this.authenticationManager = authenticationManager;
        this.jwtToken = jwtToken;
        this.userService = userService;
        this.repository = repository;
        this.encoder = encoder;
        this.roleRepository = roleRepository;
    
        

方法:/登录

    @PostMapping("/login")
    public ResponseEntity<?> login(@RequestBody AuthDto requestDto) 
        try 
            String username = requestDto.getUsername();
            Authentication authentication = authenticationManager.authenticate(
                    new UsernamePasswordAuthenticationToken(requestDto.getUsername(), requestDto.getPassword()));
            User user=userService.findByUsername(username);

            SecurityContextHolder.getContext().setAuthentication(authentication);
            String jwt = jwtToken.generateJwtToken(authentication);

            UserDetailsImpl userDetails = (UserDetailsImpl) authentication.getPrincipal();
            List<String> roles = userDetails.getAuthorities().stream()
                    .map(GrantedAuthority::getAuthority)
                    .collect(Collectors.toList());

            return ResponseEntity.ok(new JwtResponseDto(
                    jwt,
                    userDetails.getId(),
                    userDetails.getUsername(),
                    userDetails.getEmail(),
                    roles));

         catch (AuthenticationException e) 
            throw new BadCredentialsException("Invalid username or password");
        
    

方法:/signUp

    @PostMapping("/signup")
    public ResponseEntity<?> registerUser(@RequestBody CustomerDto signUpAuthDto) 
        if (repository.existsByUsername(signUpAuthDto.getUsername())) 
            return ResponseEntity
                    .badRequest()
                    .body(new MessageResponse("Error: Username is already taken"));
        
        if (repository.existsByEmail(signUpAuthDto.getEmail())) 
            return ResponseEntity
                    .badRequest()
                    .body(new MessageResponse("Error: Email is already in use"));
        
        if (signUpAuthDto.getPassword() !=null && !signUpAuthDto.getPassword().equals(signUpAuthDto.getConfirm())) 
            return  ResponseEntity
                    .badRequest()
                    .body(new MessageResponse("Error: You entered two different passwords. Please try again"));
        

        User user = new User(signUpAuthDto.getUsername(),
                signUpAuthDto.getEmail(),
                encoder.encode(signUpAuthDto.getPassword()));
                encoder.encode(signUpAuthDto.getConfirm());

        Set<Role> strRoles = signUpAuthDto.getRole();
        Set<Role> roles = new HashSet<>();

        if (strRoles == null) 
            Role userRole = roleRepository.findByName(EnumRole.ROLE_USER)
                    .orElseThrow(()-> new RuntimeException("Error: Role is not found"));
            roles.add(userRole);
         else 
            strRoles.forEach(role -> 
                if ("admin".equals(role)) 
                    Role adminRole = roleRepository.findByName(EnumRole.ROLE_ADMIN)
                            .orElseThrow(()-> new RuntimeException("Error: Role is not found"));

                    roles.add(adminRole);
                 else 
                    Role userRole = roleRepository.findByName(EnumRole.ROLE_USER)
                            .orElseThrow(()-> new RuntimeException("Error: Role is not found"));
                    roles.add(userRole);
                
            );
        

        user.setRoles(roles);
        repository.save(user);

        return ResponseEntity.ok(new MessageResponse("User registered successfully!"));

    

非常感谢任何帮助!

【问题讨论】:

【参考方案1】:

此处模拟身份验证的最佳方法是使用 Spring Security Test 依赖项的 SecurityMockMvcRequestPostProcessors 之一:

<dependency>
  <groupId>org.springframework.security</groupId>
  <artifactId>spring-security-test</artifactId>
  <scope>test</scope>
</dependency>

因此,您的 Spring MVC 控制器可以使用 @WebMvcTest 编写测试并获得自动配置的 MockMvc 实例。

通过这种方式,您可以使用模拟的 Servlet 环境测试您的端点,并且可以模拟任何您想要的身份验证或登录用户。

this.mockMvc
    .perform(
      post("/api/auth/signup")
        .contentType(MediaType.APPLICATION_JSON)
        .content("YOUR_PAYLOAD")
        .with(csrf())
        .with(SecurityMockMvcRequestPostProcessors.user("duke"))
    )
    .andExpect(status().isOk())

更多信息请关注MockMvc guide。

【讨论】:

这太棒了!感谢您提供信息。

以上是关于如何用 mockito 测试这个类?的主要内容,如果未能解决你的问题,请参考以下文章

如何用 Mockito 模拟 JmsTemplate?

如何用mockito+spring进行单元测试

mockito使用心得

Mockito 简明教程

Mockito 简明教程

Android单元测试系列-Mock之Mockito