【问题标题】:How to test spring configuration classes?如何测试弹簧配置类?
【发布时间】:2016-04-26 20:21:07
【问题描述】:

我有一个带有配置类的 spring 应用程序,其中实例化了 beans。

应用类:

@Configuration
@EnableAspectJAutoProxy
@EnableSpringDataWebSupport
@EnableTransactionManagement
@ComponentScan(basePackageClasses = Application.class)
@PropertySource(value = {"classpath:foo.properties"})
@EnableJpaRepositories(basePackageClasses = Application.class)
@EnableJpaAuditing
public class Application {

    @Inject
    private Environment env;

    @Bean
    JndiTemplate jndiTemplate() {
        return new JndiTemplate();
    }

    @Bean
    public DataSource dataSource() {        
        DataSource dataSource = getDataSource();
        if (dataSource == null) {
            dataSource = new BasicDataSource();
            ((BasicDataSource) dataSource).setUsername(env.getProperty("jdbc.user"));
            ((BasicDataSource) dataSource).setPassword(env.getProperty("jdbc.password""));

            ((BasicDataSource) dataSource).setDriverClassName(env.getProperty("jdbc.driverClassName"));
            ((BasicDataSource) dataSource).setUrl(env.getProperty("jdbc.url"));
        }
        return dataSource;
    }

    @Bean
    public PlatformTransactionManager transactionManager() {
        EntityManagerFactory factory = entityManagerFactory().getObject();
        return new JpaTransactionManager(factory);
    }

    //....
}

MvcConfiguration 类:

@Configuration
@ComponentScan(basePackageClasses = Application.class, includeFilters = @Filter({Controller.class, Component.class}), useDefaultFilters = true)
class MvcConfiguration extends WebMvcConfigurationSupport {
    private static final String MESSAGES = "classpath:/i18n";

    private static final String VIEW_PREFIX = "/WEB-INF/views/";

    @Inject
    private Environment env;

    @Override
    public RequestMappingHandlerMapping requestMappingHandlerMapping() {
        RequestMappingHandlerMapping requestMappingHandlerMapping = super.requestMappingHandlerMapping();
        requestMappingHandlerMapping.setUseSuffixPatternMatch(false);
        requestMappingHandlerMapping.setUseTrailingSlashMatch(true);

        return requestMappingHandlerMapping;
    }

    @Bean(name = "messageSource")
    public MessageSource messageSource() {
        ReloadableResourceBundleMessageSource messageSource = new ReloadableResourceBundleMessageSource();
        messageSource.setBasename(MESSAGES);
        messageSource.setCacheSeconds(5);

        return messageSource;
    }

    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/static/").addResourceLocations("/static/**");
    }

    @Bean
    public MultipartResolver filterMultipartResolver(){
        CommonsMultipartResolver resolver = new CommonsMultipartResolver();
        resolver.setMaxUploadSize(Long.parseLong(env.getProperty("multipart.max.size")));
        return resolver;
    }

    //....

}

和SecurityConfiguration类:

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

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }


    //....

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        //Logout por POST con el valor de token csrf
        http.authorizeRequests()
                .antMatchers("/static/**").permitAll()
                .anyRequest().authenticated()
                .and()
            .formLogin()
                .loginPage("/login")
                .permitAll()
                .failureUrl("/login?error=1")
                .loginProcessingUrl("/authenticate")
                .and()
            .logout()
                .logoutUrl("/logout")
                .logoutSuccessUrl("/signin")
                .permitAll();
    }

}

如何使用 JUnit 测试它们?如何测试bean是在spring上下文中创建的?

【问题讨论】:

    标签: java spring spring-mvc junit


    【解决方案1】:

    我相信这只能通过集成测试来实现。

    单元测试的目的不是检查整个 Spring 上下文是否创建成功。

    您可以使用单元测试来测试每个配置方法,通过使用 mock 等来检查它们是否正常,但整个 Spring Context 是一个集成测试。

    我过去常常通过 Spring Docs 所谓的“Spring Unit Test”来执行此配置测试(对我来说,这更像是控制器 + 视图的集成测试)

    这个想法是,如果您可以为控制器集成测试运行 Spring 上下文,那么您的配置就可以了。

    spring 文档中有一整章介绍了如何进行这种测试。 http://docs.spring.io/spring/docs/current/spring-framework-reference/html/testing.html

    【讨论】:

      【解决方案2】:

      对于基本 bean 测试和一些高级属性配置,我使用 ApplicationContextRunner() 来测试这些类。

      https://dev.to/stack-labs/how-to-test-configuration-class-in-spring-boot-16ai

      对于 Spring Security @Configuration Classes,我将加载该类,然后定义一个控制器以查看其上的安全性是否正确定义。

      【讨论】:

        【解决方案3】:

        您应该能够使用 @ContextConfiguration 注释测试配置。例如,SecurityConfiguration 类可以这样测试:

        @RunWith(SpringJUnit4ClassRunner.class)
        @ContextConfiguration(classes = SecurityConfiguration.class) 
        class SecurityConfigurationTest {
        
            @Autowired
            SecurityConfiguration securityConfiguration;
        
            @Test
            public void passwordEncoderTest() throws Exception {
                final BCryptPasswordEncoder encoder = securityConfiguration.passwordEncoder();
                final String encodedPassword = encoder.encode("password");
                assertNotNull(encodedPassword);
            }
        }
        

        【讨论】:

        • 嘿 kyleus,为什么你使用 @Autowire 而不是模拟或注入模拟。请提出建议。
        【解决方案4】:

        一句话——“不要”,那是疯了。

        您真正想要的是更高级别的测试,这些测试利用您的 Spring 配置,但仍然关注行为而不是实现

        例如,查看您的安全配置 - 您并不真正关心 configure 方法是否被调用,或者它做了什么,您想要测试的是:

        1. 静态页面不需要身份验证
        2. 其他页面确实需要身份验证
        3. 登录作品
        4. 注销作品

        将 Spring 用于 DI 和安全性只是 这些东西是如何实现的,而您的测试应该关注这些东西实际工作的事实。

        【讨论】:

          【解决方案5】:

          您可以在 JUnit 测试中构建上下文,前提是所有 bean 都可以在测试环境中实例化。您可以使用AnnotationConfigApplicationContext 及其scan() 方法来执行此操作。

          这样的测试应该足以快速验证配置。您可以从那里开始,从上下文中获取 bean 以进行更复杂的测试。

          几个陷阱:

          • 可能不适用于延迟初始化的 bean
            • 您可能需要使用 getBean() 从上下文中实际请求这样一个类的实例,以确保它已创建 - 您可以通过这种方式测试该期望
          • 可能并不总是可行的,例如如果您有一些数据库连接作为依赖项并且在测试环境中无权访问数据库
            • 您可能需要模拟此类 bean 以用于测试目的

          【讨论】:

            猜你喜欢
            • 2011-11-27
            • 2012-11-02
            • 1970-01-01
            • 1970-01-01
            • 2011-09-11
            • 2019-09-26
            • 2021-12-12
            • 2013-10-10
            相关资源
            最近更新 更多