【问题标题】:Mockito doesn't mocking with @PreAuthorize and Spring BootMockito 不使用 @PreAuthorize 和 Spring Boot 模拟
【发布时间】:2016-01-04 13:31:20
【问题描述】:

我对 Spring Security(使用 Spring Boot 1.3.1.RELEASE)和 Mockito 有很大的问题。

当我在 SampleService 类上的方法 doIt() 上使用 @PreAuthorize 时,Mockito 在测试 doItTest() 期间不会在 SampleService 内模拟方法 getValue()(在 SampleDao 类上声明)。

结果是:java.lang.AssertionError: expected:<false> but was:<true>

它的发生是因为指令

Mockito.when(dao.getValue()).thenReturn(ctrl);

当我在 SampleService 类的方法 doIt() 中使用 @PreAuthorize 时不起作用。

当我从方法 doIt() 中删除 @PreAuthorize 时,测试 doItTest() 工作正常(Mockito 正在模拟 getValue())。

但是当我在 doIt() 方法上使用 @PreAuthorize 运行另一个测试 doItDeniedTest() 时,它工作正常,因为 @PreAuthorize 抛出 AccessDeniedException。

我该如何解决?

谢谢大家。

代码:

@SpringBootApplication
public class AppApplication {

    public static void main(String[] args) {
        SpringApplication.run(AppApplication.class, args);
    }
}

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

   @Autowired
   private LogoutHandler logoutHandler;

   @Autowired
   private AuthenticationSuccessHandler authenticationSuccessHandler;

   @Autowired
   private AccessDeniedHandler accessDeniedHandler;

   @Autowired
   private AuthenticationFailureHandler authenticationFailureHandler;

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
        .authorizeRequests()
            .antMatchers("/public/**").permitAll()
            .antMatchers("/error/**").permitAll()
            .and()
        .authorizeRequests()
            .antMatchers("/").permitAll()
            .antMatchers("/adm/**").hasAnyRole(Role.ROOT,Role.ADM)
            .anyRequest().authenticated()
            .and()
        .formLogin()
            .loginPage("/login")
            .successHandler(authenticationSuccessHandler)
            .failureHandler(authenticationFailureHandler)
            .defaultSuccessUrl("/home",true)
            .permitAll()
            .and()
        .logout()
            .logoutSuccessUrl("/login")
            .permitAll()
            .addLogoutHandler(logoutHandler)
            .and()
         .exceptionHandling()
            .accessDeniedHandler(accessDeniedHandler);

    }
}


@Repository
public class SampleDao implements Dao {

   @Override
   public boolean getValue(){
     return true;
   }

}

@Service
public class SampleService implements Service{

   @Autowired
   private Dao dao;

   @Override
   @PreAuthorize(value="hasRole('USR')")
   public boolean doIt(){
     return dao.getValue();
   }

}

我的测试课是:

@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = {AppApplication.class})
@WebAppConfiguration
public class SampleServiceImplTest {
    @Mock
    private SampleDaoImpl dao;

    @Autowired
    @Qualifier("sampleServiceImpl")
    @InjectMocks
    private SampleService svc;

    @Before
    public void initMocks(){
        MockitoAnnotations.initMocks(this); 
    }   


    @Test(expected=AccessDeniedException.class)
    @WithMockUser(username="usr",roles={"ROOT"})
    public void doItDeniedTest() {
        svc.doIt();
    }

    @Test
    @WithMockUser(username="usr",roles={"USR"})
    public void doItTest() {

    Boolean ctrl = Boolean.FALSE;
    Mockito.when(dao.getValue()).thenReturn(ctrl);

    Boolean rt = svc.doIt();
    assertEquals(ctrl,rt);      
    }

}

【问题讨论】:

    标签: java spring spring-security spring-boot mockito


    【解决方案1】:

    您正在将集成测试与单元测试结合起来。不要那样做。 你有两个选择:

    1. 根本不创建 Spring 上下文,在测试中显式连接类并使用类似的模拟。这将是单元测试。
    2. 如果您想在集成测试中模拟 Spring bean,您需要将其注册到 Spring 上下文中。我写了这个blog post on the topic

    【讨论】:

    • 关于集成测试和单元测试的结合,我可以分开吗?再次感谢。
    【解决方案2】:

    阅读blog后,我改变了我的测试类。

    @RunWith(SpringJUnit4ClassRunner.class)
    @SpringApplicationConfiguration(classes = {AppApplication.class,TestConfiguration.class})
    @WebAppConfiguration
    public class SampleServiceImplTest {
    
        @Configuration
        @EnableGlobalMethodSecurity(prePostEnabled = true)
        protected static class TestConfiguration {
             @Bean
             @Primary
             public SampleDaoImpl gatSampleDaoImpl(){
                   return Mockito.mock(SampleDaoImpl.class);
             }
        }
    
        @Autowired
        private SampleDaoImpl dao;
    
        @Autowired
        private SampleService svc;
    
        @Before
        public void initMocks(){
            MockitoAnnotations.initMocks(this); 
        }   
    
    
        @Test(expected=AccessDeniedException.class)
        @WithMockUser(username="usr",roles={"ROOT"})
        public void doItDeniedTest() {
            svc.doIt();
        }
    
        @Test
        @WithMockUser(username="usr",roles={"USR"})
        public void doItTest() {
    
        Boolean ctrl = Boolean.FALSE;
        Mockito.when(dao.getValue()).thenReturn(ctrl);
    
        Boolean rt = svc.doIt();
        assertEquals(ctrl,rt);      
        }
    
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-12-25
      • 2019-06-16
      • 1970-01-01
      • 2022-01-25
      • 1970-01-01
      • 2022-12-11
      • 2019-11-19
      • 2021-05-28
      相关资源
      最近更新 更多