Mockito并没有使用@PreAuthorize和Spring Boot进行嘲弄

时间:2016-01-04 13:31:20

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

我在使用Spring Security(使用Spring Boot 1.3.1.RELEASE)和Mockito时遇到了相当大的问题。

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

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

它的发生是因为指令

Mockito.when(dao.getValue()).thenReturn(ctrl);
当我在SampleService类的方法doIt()上使用@PreAuthorize时,

不起作用。

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

但是当我在方法doItDeniedTest()上使用@PreAuthorize运行其他测试doIt()时,其工作正常,因为@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);      
    }

}

2 个答案:

答案 0 :(得分:3)

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

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

答案 1 :(得分:1)

阅读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);      
    }

}