J'ai une application de printemps et des tests d'intégration pour cette application. Je voudrais remplacer un haricot par un haricot simulé.
Mon vrai bean ressemble à ceci
@Autowired private IMyService myService;
et pour le test je voudrais qu'il soit remplacé
@Service
@Profile("!test")
public class MyService implements IMyService {
}
@Service
@Profile("test")
public class TestMyService implements IMyService {
}
Tous Je peux penser à utiliser des profils pour différents services. Par exemple:
@Service
public class TestMyService {
}
Et puis je filme automatiquement le bean comme ceci
@Service
public class MyService {
}
Y a-t-il un meilleur moyen? P >
3 Réponses :
Ma préférence personnelle est d'éviter de charger le contexte de compétition pour les tests. Par conséquent, j'aime que mon test se concentre sur un sous-ensemble de beans. Cela signifie généralement que je décris les beans que j'utilise dans les tests:
@RunWith(SpringRunner.class)
@SpringBootTest(
classes = MyTest.Cfg.class
)
public class MyTest {
@Import({
// .. some classes to import
})
@Configuration
public static class Cfg {
@Bean
public IMyService service() {
IMyService mock = Mockito.mock(IMyService.class);
when(mock.someMethod()).thenReturn("some data");
return mock;
}
}
}
Si plus de configuration est nécessaire, j'ai tendance à préparer une classe de configuration distincte pour les tests:
@RunWith(SpringRunner.class)
@SpringBootTest(
classes = MyTest.Cfg.class
)
public class MyTest {
@Import({
// .. some classes to import including TestMyService.class
})
@Configuration
public static class Cfg {
}
}
cool. Vous vous retrouvez alors avec 10, 20 ou 30 beans dans la section @Import ?
J'ai plusieurs configurations avec une application (type de modules / packages) où je configure principalement des dépendances externes (adaptateurs, ports suivants et architecture d'adaptateurs). Ce qui m'aide avec l'encapsulation. En parcourant le code, je ne vois pas plus de 6 à 8 importations dans un seul test.
Agréable! J'avais du mal à utiliser @Spybean, ce qui ne fonctionnait pas, peu importe comment je l'utilisais ... merci!
Vous pouvez nommer vos beans, dans votre cas quelque chose comme
@Qualifier("testService")
@Autowired
private IMyService myService;
et dans votre classe de test, vous pouvez demander explicitement un service de test en utilisant @Qualifier , comme
@Service("testService")
public class TestMyService implements IMyService {
}
Cette approche ne fonctionne pas lorsque IMyService est une dépendance en aval (un adaptateur) dans votre code métier. @Qualifier vous permet d'injecter le bean dans la classe de test, mais c'est très limitant.
Spring Boot a des annotations @MockBean et @SpyBean exactement à cet effet:
La déclaration est simple:
@MockBean private MyService myService;
Spring Boot y injectera Mockito mock au lieu du bean réel.