Java 如何测试spring配置类?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/34909345/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-11 16:07:09  来源:igfitidea点击:

How to test spring configuration classes?

javaspringspring-mvcjunit

提问by oscar

I have a spring application whith configuration classes where instance the beans.

我有一个 spring 应用程序,其中包含实例 bean 的配置类。

Aplication class:

应用类:

@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 class:

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;
    }

    //....

}

And SecurityConfiguration class:

和 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();
    }

}

How I can test them with JUnit? How to test the beans are created in the spring context?

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

采纳答案by renanleandrof

I believe this is will only be achieved with an Integration Test.

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

The purpose of Unit Tests are not to check if the whole Spring Context is being created with success.

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

You can test each configuration method with a Unit Test by using mocks and etc to check if they are ok, but the whole Spring Context thing is an Integration test.

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

I use to do this Configuration Test by doing what Spring Docs call "Spring Unit Test" (that for me is more like a Integration Test of the Controllers + Views)

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

The idea is that, if you can get a Spring Context running for a Controller integration Test, than your Configurations are OK.

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

There is a whole chapter on spring docs on how to do that kind of test. http://docs.spring.io/spring/docs/current/spring-framework-reference/html/testing.html

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

回答by Jiri Tousek

You could build the context in a JUnit test, provided that all the beans can be instantiated in the test environment. You can use AnnotationConfigApplicationContextand its scan()method to do this.

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

Such test should be enough for a quick verification of the config. And you can go from there, obtaining beans from the context for a more complex testing.

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

Couple of pitfalls:

几个陷阱:

  • Might not work well for lazy-initialized beans
    • You may need to actually request an instance from the context using getBean()for such a class to ensure it is created - you can test that expectation this way
  • May not be always possible, e.g. if you have some database connection as a dependency and don't have access to the database in the test environment
    • You may need to mock such beans for the test's purposes
  • 可能不适用于延迟初始化的 bean
    • 您可能需要实际从上下文中请求使用getBean()此类类的实例以确保它已创建 - 您可以通过这种方式测试该期望
  • 可能并不总是可能的,例如,如果您有一些数据库连接作为依赖项并且在测试环境中无权访问数据库
    • 为了测试的目的,您可能需要模拟此类 bean

回答by tddmonkey

In a word - "don't", that way lays madness.

总之一句话——“不要”,那样就让人发疯了。

What you really want is higher level tests that make use of your Spring configuration but are still focused on behaviournot implementation.

您真正想要的是使用 Spring 配置但仍关注行为而非实现的更高级别的测试。

For example, looking at your security configuration - you don't really care that the configuremethod is called, or what it does, what you want to test for is:

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

  1. Static pages don't require authentication
  2. Other pages do require authentication
  3. Logging in works
  4. Logging out works
  1. 静态页面不需要身份验证
  2. 其他页面确实需要身份验证
  3. 登录作品
  4. 注销工作

Using Spring for DI and security is merely howthose things are implemented whereas your tests should be focused on the fact those things actually work.

使用Spring DI和安全仅仅是如何的那些东西来实现,而你的测试应该着眼于那些东西实际上工作。

回答by kyleus

You should be able to test the configuration using the @ContextConfigurationannotation. For Example, the SecurityConfiguration class can be tested like this:

您应该能够使用@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);
    }
}

回答by Kevin Davin

For basic bean testing and some advanced properties configuration, I use the ApplicationContextRunner()to test those classes.

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

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

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

For Spring Security @Configuration Classes, I would load the class and then define a controller to see if the security on it is correctly defined.

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