web-dev-qa-db-ja.com

スプリング構成クラスをテストする方法は?

インスタンスがBeanである構成クラスを使用したSpringアプリケーションがあります。

アプリケーションクラス:

@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をテストする方法は、春のコンテキストで作成されますか?

12
oscar

これは統合テストでのみ達成されると思います。

単体テストの目的は、Spring Context全体が正常に作成されているかどうかを確認することではありません。

モックなどを使用してユニットテストで各構成メソッドをテストし、それらが正常かどうかを確認できますが、Spring Context全体が統合テストです。

私はSpring Docsが「Spring Unit Test」と呼ぶものを実行することでこの構成テストを実行します(私にとっては、コントローラとビューの統合テストのようなものです)

コントローラー統合テスト用に実行されているSpringコンテキストを取得できる場合、構成は問題ありません。

この種のテストを行う方法については、春のドキュメントの章全体があります。 http://docs.spring.io/spring/docs/current/spring-framework-reference/html/testing.html

9
renanleandrof

一言で言えば-「しない」と、その方法は狂気を生む。

本当に必要なのは、Springの構成を使用するが、まだbehaviourではなくimplementationに焦点を当てた高レベルのテストです。

たとえば、セキュリティ構成を見ると、configureメソッドが呼び出されるかどうか、または何をテストするかはあまり気になりません。

  1. 静的ページは認証を必要としません
  2. 他のページでは認証が必要です
  3. 作品にログインする
  4. ログアウト機能

SpringをDIとセキュリティに使用することは、単にhowそれらが実装されているのに対して、テストはそれらの要素が実際に機能するという事実に焦点を合わせるべきです。

23
tddmonkey

@ 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);
    }
}
9
kyleus

すべてのBeanをテスト環境でインスタンス化できる場合、JUnitテストでコンテキストを構築できます。 AnnotationConfigApplicationContext およびそのscan()メソッドを使用してこれを行うことができます。

このようなテストは、構成の迅速な検証に十分なはずです。そして、そこから進んで、コンテキストからBeanを取得して、より複雑なテストを行うことができます。

落とし穴のカップル:

  • 遅延初期化されたBean ではうまく機能しない可能性があります
    • このようなクラスのgetBean()を使用して、実際にコンテキストからインスタンスを要求して、作成されていることを確認する必要がある場合があります。この方法でこの期待をテストできます。
  • 常に可能であるとは限りません。依存関係として何らかのデータベース接続があり、テスト環境でデータベースにアクセスできない場合
    • テストの目的でこのようなBeanをモックする必要がある場合があります
1
Jiri Tousek