J'ai une application Spring avec des classes de configuration où les beans sont par exemple.
Classe d'application:
@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);
}
//....
}
Classe 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;
}
//....
}
Et classe 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();
}
}
Comment puis-je les tester avec JUnit? Comment tester les haricots créés dans le contexte printanier?
Je crois que cela ne sera réalisé qu'avec un test d'intégration.
Le but des tests unitaires n'est pas de vérifier si l'ensemble du contexte Spring est créé avec succès.
Vous pouvez tester chaque méthode de configuration avec un test unitaire en utilisant des simulations et etc pour vérifier si elles sont correctes, mais tout le truc du contexte Spring est un test d'intégration.
J'utilise pour faire ce test de configuration en faisant ce que Spring Docs appelle "Spring Unit Test" (qui pour moi ressemble plus à un test d'intégration des contrôleurs + vues)
L'idée est que, si vous pouvez exécuter un contexte Spring pour un test d'intégration de contrôleur, vos configurations sont OK.
Il y a tout un chapitre sur les documents du printemps sur la façon de faire ce genre de test. http://docs.spring.io/spring/docs/current/spring-framework-reference/html/testing.html
En un mot - "ne faites pas", de cette façon jette la folie.
Ce que vous voulez vraiment, ce sont des tests de niveau supérieur qui utilisent votre configuration Spring mais qui sont toujours axés sur comportement pas implémentation.
Par exemple, en regardant votre configuration de sécurité - peu vous importe que la méthode configure
soit appelée, ou ce qu'elle fait, ce que vous voulez tester est:
Utiliser Spring pour DI et la sécurité est simplement comment ces choses sont implémentées alors que vos tests doivent être axés sur le fait que ces choses fonctionnent réellement.
Vous devriez pouvoir tester la configuration à l'aide de l'annotation @ ContextConfiguration. Par exemple, la classe SecurityConfiguration peut être testée comme ceci:
@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);
}
}
Vous pouvez créer le contexte dans un test JUnit, à condition que tous les beans puissent être instanciés dans l'environnement de test. Vous pouvez utiliser AnnotationConfigApplicationContext et sa méthode scan()
pour ce faire.
Un tel test devrait être suffisant pour une vérification rapide de la configuration. Et vous pouvez partir de là, obtenir des beans à partir du contexte pour un test plus complexe.
Quelques pièges:
getBean()
pour une telle classe pour vous assurer qu'elle est créée - vous pouvez tester cette attente de cette façon