Avec le bean Spring Boot 2.1 est désactivé par défaut, ce qui est une bonne chose.
Cependant, j'ai quelques tests où je remplace les beans par des instances simulées utilisant Mockito. Avec le paramètre par défaut, les tests avec une telle configuration échoueront en raison du remplacement du bean.
La seule façon dont j'ai trouvé le travail, était d'activer le bean écrasant via les propriétés de l'application:
spring.main.allow-bean-definition-overriding=true
Cependant, j'aimerais vraiment que la configuration de définition de bean soit minimale pour ma configuration de test, ce qui serait signalé par printemps avec désactivation de la substitution.
Les haricots que je prends sont soit
Ce que je pensais devrait fonctionner dans la configuration de test en remplaçant le bean et en y insérant un @Primary
, comme nous en avons l'habitude pour les configurations de source de données. Cela n'a cependant aucun effet et m'a amené à me demander: le @Primary
et le haricot désactivé sont-ils contradictoires?
Quelques exemples:
package com.stackoverflow.foo;
@Service
public class AService {
}
package com.stackoverflow.foo;
public class BService {
}
package com.stackoverflow.foo;
@Configuration
public BaseConfiguration {
@Bean
@Lazy
public BService bService() {
return new BService();
}
}
package com.stackoverflow.bar;
@Configuration
@Import({BaseConfiguration.class})
public class TestConfiguration {
@Bean
public BService bService() {
return Mockito.mock(BService.class);
}
}
Remplacer les haricots signifie qu'il ne peut y avoir qu'un seul haricot avec un nom ou un identifiant unique dans le contexte. Ainsi, vous pouvez fournir deux haricots de la manière suivante:
package com.stackoverflow.foo;
@Configuration
public class BaseConfiguration {
@Bean
@Lazy
public BService bService1() {
return new BService();
}
}
package com.stackoverflow.bar;
@Configuration
@Import({BaseConfiguration.class})
public class TestConfiguration {
@Bean
public BService bService2() {
return Mockito.mock(BService.class);
}
}
Si vous ajoutez @Primary
, le bean primaire sera injecté par défaut dans:
@Autowired
BService bService;
spring.main.allow-bean-definition-overriding=true
peut être placé dans des configurations de test. Si vous avez besoin de tests d'intégration approfondis, vous devrez éventuellement remplacer les beans. C'est inévitable.
Je voulais juste souligner une fois de plus que même si la réponse correcte a déjà été fournie, cela implique que votre bean aura des noms différents, donc techniquement, il ne s'agit pas d'une substitution. Le remplacement réel, si vous en avez besoin parce que vous utilisez @Qualifiers
, @Resources
ou quelque chose de similaire, à partir de Spring Boot 2.X n'est possible qu'avec spring.main.allow-bean-definition-overriding=true
Mise à jour: Soyez prudent avec DSL de définition de haricot Kotlin. Au démarrage de printemps, il faudra un ApplicationContextInitializer personnalisé, comme suit:
class BeansInitializer : ApplicationContextInitializer<GenericApplicationContext> {
override fun initialize(context: GenericApplicationContext) =
beans.initialize(context)
}
Maintenant, si vous décidez de remplacer l'un de ces beans basés sur DSL dans votre test via la méthode @Primary @Bean
, cela ne fonctionnera pas. L'initialiseur démarrera après les méthodes @Bean
et vous obtiendrez toujours le bean initial basé sur DSL dans vos tests, même avec @Primary
sur le test @Bean
. Une autre option consisterait également à créer un initialiseur de test pour vos tests et à les répertorier dans vos propriétés de test, comme suit (l'ordre est important):
context:
initializer:
classes: com.yuranos.BeansInitializer, com.yuranos.TestBeansInitializer
Bean Definition DSL prend également en charge la propriété primaire via:
bean(isPrimary=true) {...}
- dont vous aurez besoin pour éliminer toute ambiguïté lorsque vous essayez d’injecter un haricot, cependant main:allow-bean-definition-overriding: true
n’est pas nécessaire si vous utilisez la méthode DSL pure.
(Spring Boot 2.1.3)
Il est permis de remplacer @Component par @Bean par défaut. Dans ton cas
@Service
public class AService {
}
@Component
public class BService {
@Autowired
public BService() { ... }
}
@Configuration
@ComponentScan
public BaseConfiguration {
}
@Configuration
// WARNING! Doesn't work with @SpringBootTest annotation
@Import({BaseConfiguration.class})
public class TestConfiguration {
@Bean // you allowed to override @Component with @Bean.
public BService bService() {
return Mockito.mock(BService.class);
}
}