在 Spring App 中将 MockitoMVC 与 Junit 一起使用时出现 *** 错误

Posted

技术标签:

【中文标题】在 Spring App 中将 MockitoMVC 与 Junit 一起使用时出现 *** 错误【英文标题】:*** error while using MockitoMVC with Junit in Spring App 【发布时间】:2020-11-28 17:10:33 【问题描述】:

我正在尝试测试我的 Spring 应用程序,该应用程序由 JWT auth 和 Junit 和 Mockmvc 组成。注册测试按预期工作。但是在尝试测试登录时,会显示 ***Error。在 JWTAuthenticationFilter.java 中,数据被成功接收。但是在显示该错误之后。请帮帮我。谢谢!

错误:


java.lang.***Error
    at org.mockito.internal.invocation.MatchersBinder.bindMatchers(MatchersBinder.java:25)
    at org.mockito.internal.handler.MockHandlerImpl.handle(MockHandlerImpl.java:59)
    at org.mockito.internal.handler.NullResultGuardian.handle(NullResultGuardian.java:29)
    at org.mockito.internal.handler.InvocationNotifierHandler.handle(InvocationNotifierHandler.java:35)
    at org.mockito.internal.creation.bytebuddy.MockMethodInterceptor.doIntercept(MockMethodInterceptor.java:63)
    at org.mockito.internal.creation.bytebuddy.MockMethodInterceptor.doIntercept(MockMethodInterceptor.java:49)
    at org.mockito.internal.creation.bytebuddy.MockMethodInterceptor$DispatcherDefaultingToRealMethod.interceptSuperCallable(MockMethodInterceptor.java:110)
    at org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder$MockitoMock$310380589.encode(Unknown Source)
    at org.springframework.security.authentication.dao.DaoAuthenticationProvider.prepareTimingAttackProtection(DaoAuthenticationProvider.java:142)
    at org.springframework.security.authentication.dao.DaoAuthenticationProvider.retrieveUser(DaoAuthenticationProvider.java:106)
    at org.springframework.security.authentication.dao.AbstractUserDetailsAuthenticationProvider.authenticate(AbstractUserDetailsAuthenticationProvider.java:144)
    at org.springframework.security.authentication.ProviderManager.authenticate(ProviderManager.java:175)
    at org.springframework.security.authentication.ProviderManager.authenticate(ProviderManager.java:200)
    at org.springframework.security.con

WebSecurity.java


@EnableWebSecurity
public class WebSecurity extends WebSecurityConfigurerAdapter 
    private UserDetailsServiceImpl userDetailsService;
    private BCryptPasswordEncoder bCryptPasswordEncoder;


    public WebSecurity(UserDetailsServiceImpl userDetailsService, BCryptPasswordEncoder bCryptPasswordEncoder) 
        this.userDetailsService = userDetailsService;
        this.bCryptPasswordEncoder = bCryptPasswordEncoder;
    

    @Override
    protected void configure(HttpSecurity http) throws Exception 
        http.cors().and().csrf().disable().authorizeRequests()
                .antMatchers(HttpMethod.POST, SecurityConstants.SIGN_UP_URL).permitAll()
                .anyRequest().authenticated()
                .and()
                .addFilter(new JWTAuthenticationFilter(authenticationManager()))
                .addFilter(new JWTAuthorizationFilter(authenticationManager()))
                // this disables session creation on Spring Security
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
    

    @Override
    @Bean
    public AuthenticationManager authenticationManagerBean() throws Exception
        return super.authenticationManagerBean();
    

    @Override
    public void configure(AuthenticationManagerBuilder auth) throws Exception 
        auth.parentAuthenticationManager(authenticationManagerBean())
                .userDetailsService(userDetailsService)
                .passwordEncoder(bCryptPasswordEncoder);
    


UserControllerTest.java


@RunWith(SpringRunner.class)
@SpringBootTest
@AutoConfigureMockMvc
@AutoConfigureJsonTesters
public class UserControllerTest 
    @Autowired
    private MockMvc mvc;

    @Autowired
    private JacksonTester<User> json;

    @Autowired
    private JacksonTester<CreateUserRequest> jsonN;

    @MockBean
    private UserRepository userRepository;

    @MockBean
    private BCryptPasswordEncoder encoder;

    private  CreateUserRequest r;

    @Before
    public void setup()
        r = new CreateUserRequest();
        r.setUsername("ujjwal2102");
        r.setPassword("ujjwal21");
        r.setConfirmPassword("ujjwal21");


    

    @Test
    public void createUserTest() throws Exception
        signup();
    

    @Test
    public void loginUserTest() throws Exception
        signup();
        login();
    

    public void signup() throws Exception
        when(encoder.encode("ujjwal21")).thenReturn("ujjwal21");

        mvc.perform(
                post(new URI("/api/user/create"))
                        .content(jsonN.write(r).getJson())
                        .contentType(MediaType.APPLICATION_JSON_UTF8)
                        .accept(MediaType.APPLICATION_JSON_UTF8))
                .andExpect(status().isOk())
                .andExpect(jsonPath("$.id",is(0)))
                .andExpect(jsonPath("$.username",is("ujjwal2102")));
    

    public void login() throws Exception

        User user = new User();
        user.setUsername("ujjwal2102");
        user.setPassword("ujjwal21");

        when(encoder.encode("ujjwal21")).thenReturn("ujjwal21");
        mvc.perform(
                    post(new URI("/login"))
                        .content(json.write(user).getJson())
                        .contentType(MediaType.APPLICATION_JSON_UTF8)
                        .accept(MediaType.APPLICATION_JSON_UTF8))
                .andExpect(status().isOk());



    




用户.java


@Entity
@Table(name = "user")
public class User 

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @JsonProperty
    private long id;
    
    @Column(nullable = false, unique = true)
    @JsonProperty
    private String username;

    @JsonProperty(access = JsonProperty.Access.WRITE_ONLY)
    @Column(nullable = false)
    private String password;

    @OneToOne(cascade = CascadeType.ALL)
    @JoinColumn(name = "cart_id", referencedColumnName = "id")
    @JsonIgnore
    private Cart cart;

    public String getPassword() 
        return password;
    

    public void setPassword(String password) 
        this.password = password;
    


    public Cart getCart() 
        return cart;
    

    public void setCart(Cart cart) 
        this.cart = cart;
    

    public long getId() 
        return id;
    

    public void setId(long id) 
        this.id = id;
    

    public String getUsername() 
        return username;
    

    public void setUsername(String username) 
        this.username = username;
    
    
    
    


JWTAuthenticationFilter.java


public class JWTAuthenticationFilter extends UsernamePasswordAuthenticationFilter 
    private AuthenticationManager authenticationManager;

    public JWTAuthenticationFilter(AuthenticationManager authenticationManager) 
        this.authenticationManager = authenticationManager;
    

    @Override
    public Authentication attemptAuthentication(HttpServletRequest req,
                                                HttpServletResponse res) throws AuthenticationException 
        try 
            User creds = new ObjectMapper()
                    .readValue(req.getInputStream(), User.class);
            System.out.println("USERNAME-----" + creds.getUsername());
            return authenticationManager.authenticate(
                    new UsernamePasswordAuthenticationToken(
                            creds.getUsername(),
                            creds.getPassword(),
                            new ArrayList<>())
            );
         catch (IOException e) 
            throw new RuntimeException(e);
        
    

    @Override
    protected void successfulAuthentication(HttpServletRequest req,
                                            HttpServletResponse res,
                                            FilterChain chain,
                                            Authentication auth) throws IOException, ServletException 

        String token = JWT.create()
                .withSubject(((org.springframework.security.core.userdetails.User) auth.getPrincipal()).getUsername())
                .withExpiresAt(new Date(System.currentTimeMillis() + SecurityConstants.EXPIRATION_TIME))
                .sign(HMAC512(SecurityConstants.SECRET.getBytes()));
        System.out.println("TOKEN----" + token);
        res.addHeader(SecurityConstants.HEADER_STRING, SecurityConstants.TOKEN_PREFIX + token);
    

【问题讨论】:

某些东西正在递归调用自己。顺便说一句,您发布的日志不完整,您介意发布完整的日志 【参考方案1】:

我注意到一个错误可能会或可能不会解决您的问题,但可能会影响您的身份验证过程。

new UsernamePasswordAuthenticationToken(
    creds.getUsername(), 
    creds.getPassword(), 
    new ArrayList<>()) // with autorities, the user is authenticated

new UsernamePasswordAuthenticationToken(
    creds.getUsername(), 
    creds.getPassword()) // without autorities, the user is not authenticated

autorities 的构造函数通常在认证成功后被 AuthentificationManager 使用。过滤器使用构造函数 without 传递给 AuthentificationManager。

Spring Security Javadoc

查看日志,问题似乎出在您未提供的 Spring 安全配置中。您可能已经在身份验证提供程序中进行了递归调用。

【讨论】:

感谢您的回复,但这并没有解决错误。 我已经添加了 WebSecurity.java。

以上是关于在 Spring App 中将 MockitoMVC 与 Junit 一起使用时出现 *** 错误的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Jetty 上的 Spring 应用程序中将 jsessionid cookie 路径更改为服务器根目录?

Android项目 app项目 java.lang.ClassNotFoundException: javax.xml.bind.JAXBException 出错解决办法不是java或spring项目

无法在测试中将 App Delegate 强制转换为 App Delegate

在 Spring 中将 @Cacheable 用于非参数方法

在 Spring 中将原型列表注入 Singleton bean

如何在 Spring 中将 OrderBy 与 JPARepository 一起使用