インスタンスが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をテストする方法は、春のコンテキストで作成されますか?
これは統合テストでのみ達成されると思います。
単体テストの目的は、Spring Context全体が正常に作成されているかどうかを確認することではありません。
モックなどを使用してユニットテストで各構成メソッドをテストし、それらが正常かどうかを確認できますが、Spring Context全体が統合テストです。
私はSpring Docsが「Spring Unit Test」と呼ぶものを実行することでこの構成テストを実行します(私にとっては、コントローラとビューの統合テストのようなものです)
コントローラー統合テスト用に実行されているSpringコンテキストを取得できる場合、構成は問題ありません。
この種のテストを行う方法については、春のドキュメントの章全体があります。 http://docs.spring.io/spring/docs/current/spring-framework-reference/html/testing.html
一言で言えば-「しない」と、その方法は狂気を生む。
本当に必要なのは、Springの構成を使用するが、まだbehaviourではなくimplementationに焦点を当てた高レベルのテストです。
たとえば、セキュリティ構成を見ると、configure
メソッドが呼び出されるかどうか、または何をテストするかはあまり気になりません。
SpringをDIとセキュリティに使用することは、単にhowそれらが実装されているのに対して、テストはそれらの要素が実際に機能するという事実に焦点を合わせるべきです。
@ 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);
}
}
すべてのBeanをテスト環境でインスタンス化できる場合、JUnitテストでコンテキストを構築できます。 AnnotationConfigApplicationContext およびそのscan()
メソッドを使用してこれを行うことができます。
このようなテストは、構成の迅速な検証に十分なはずです。そして、そこから進んで、コンテキストからBeanを取得して、より複雑なテストを行うことができます。
落とし穴のカップル:
getBean()
を使用して、実際にコンテキストからインスタンスを要求して、作成されていることを確認する必要がある場合があります。この方法でこの期待をテストできます。