Spriječite izvršavanje ApplicationNunner ili CommandLineRunner zrna tijekom testiranja junita

1. Pregled

U ovom uputstvu pokazat ćemo kako možemo spriječiti grah vrste ApplicationRunner ili CommandLineRunner od pokretanja tijekom integracijskih testova Spring Boot.

2. Primjer prijave

Naš se primjer aplikacije sastoji od pokretača naredbenog retka, pokretača aplikacije i graha usluge zadataka.

Izvođač naredbenog retka poziva službu zadataka izvršiti metodom, kako biste izvršili zadatak pri pokretanju aplikacije:

@Component javna klasa CommandLineTaskExecutor implementira CommandLineRunner {private TaskService taskService; javni CommandLineTaskExecutor (TaskService taskService) {this.taskService = taskService; } @Override public void run (String ... args) baca izuzetak {taskService.execute ("zadatak pokretača naredbenog retka"); }} 

Na isti način, pokretač aplikacije komunicira sa službom zadataka radi izvođenja drugog zadatka:

@Component javna klasa ApplicationRunnerTaskExecutor implementira ApplicationRunner {private TaskService taskService; javni ApplicationRunnerTaskExecutor (TaskService taskService) {this.taskService = taskService; } @Override public void run (ApplicationArguments args) baca izuzetak {taskService.execute ("task runner task"); }} 

Konačno, služba zadataka odgovorna je za izvršavanje zadataka svog klijenta:

@Service javna klasa TaskService {private static Logger logger = LoggerFactory.getLogger (TaskService.class); javno void izvršavanje (zadatak niza) {logger.info ("do" + zadatak); }} 

Također, imamo i klasu aplikacije Spring Boot koja čini da sve to funkcionira:

@SpringBootApplication javna klasa ApplicationCommandLineRunnerApp {public static void main (String [] args) {SpringApplication.run (ApplicationCommandLineRunnerApp.class, args); }}

3. Testiranje očekivanog ponašanja

The ApplicationRunnerTaskExecutor i CommandLineTaskExecutor pokrenite nakon što Spring Boot učita kontekst aplikacije.

To možemo provjeriti jednostavnim testom:

Klasa @SpringBootTest RunApplicationIntegrationTest {@SpyBean ApplicationRunnerTaskExecutor applicationRunnerTaskExecutor; @SpyBean CommandLineTaskExecutor commandLineTaskExecutor; @Test void whenContextLoads_thenRunnersRun () baca iznimku {verify (applicationRunnerTaskExecutor, times (1)). Run (any ()); verify (commandLineTaskExecutor, puta (1)). run (any ()); }}

Kao što vidimo, koristimo SpyBean napomena za primjenu Mockito špijuna na ApplicationRunnerTaskExecutor i CommandLineTaskExecutor grah. Na taj način možemo provjeriti je li trčanje metoda svakog od ovih graha zvala se jednom.

U sljedećim odjeljcima vidjet ćemo razne načine i tehnike za sprječavanje ovog zadanog ponašanja tijekom naših testova integracije Spring Boot.

4. Prevencija putem proljetnih profila

Jedan od načina na koji možemo spriječiti pokretanje ove dvojice je dodavanjem bilješki @Profil:

@Profile ("! Test") @Component javna klasa CommandLineTaskExecutor implementira CommandLineRunner {// isto kao i prije}
@Profile ("! Test") @Component javna klasa ApplicationRunnerTaskExecutor implementira ApplicationRunner {// isto kao i prije}

Nakon gore navedenih promjena nastavljamo s našim testom integracije:

@ActiveProfiles ("test") @SpringBootTest klasa RunApplicationWithTestProfileIntegrationTest {@Autowired private ApplicationContext context; @Test void whenContextLoads_thenRunnersAreNotLoaded () {assertNotNull (context.getBean (TaskService.class)); assertThrows (NoSuchBeanDefinitionException.class, () -> context.getBean (CommandLineTaskExecutor.class), "CommandLineRunner ne treba učitavati tijekom ovog testa integracije"); assertThrows (NoSuchBeanDefinitionException.class, () -> context.getBean (ApplicationRunnerTaskExecutor.class), "ApplicationRunner ne treba učitavati tijekom ovog testa integracije"); }}

Kao što vidimo, gornji testni razred označili smo s @ActiveProfiles ("test") napomena, što znači da neće povezati one s oznakama @Profile (“! Test”). Kao rezultat, ni CommandLineTaskExecutor grah niti ApplicationRunnerTaskExecutor grah je uopće opterećen.

5. Prevencija putem ConditionalOnProperty Bilješka

Ili možemo konfigurirati njihovo ožičenje prema svojstvu, a zatim koristiti ConditionalOnProperty napomena:

@ConditionalOnProperty (prefix = "application.runner", value = "enabled", havingValue = "true", matchIfMissing = true) @Component javna klasa ApplicationRunnerTaskExecutor provodi ApplicationRunner {// isto kao i prije} 
@ConditionalOnProperty (prefix = "command.line.runner", value = "enabled", havingValue = "true", matchIfMissing = true) @Component javna klasa CommandLineTaskExecutor implementira CommandLineRunner {// isto kao i prije}

Kao što vidimo, the ApplicationRunnerTaskExecutor i CommandLineTaskExecutor su omogućene prema zadanim postavkama, a možemo ih onemogućiti ako sljedeća svojstva postavimo na lažno:

  • command.line.runner.enabled
  • aplikacija.runner.enabled

Dakle, u našem testu, postavili smo ta svojstva na lažno a ni ApplicationRunnerTaskExecutor ni CommandLineTaskExecutor grah se učitava u kontekst aplikacije:

@SpringBootTest (svojstva = {"command.line.runner.enabled = false", "application.runner.enabled = false"}) klasa RunApplicationWithTestPropertiesIntegrationTest {// isto kao i prije}

Sada, iako nam gore navedene tehnike pomažu u postizanju cilja, postoje slučajevi u kojima želimo testirati jesu li svi proljetni grah ispravno učitani i ožičeni.

Na primjer, možda bismo htjeli testirati da li TaskService grah se pravilno ubrizgava u CommandLineTaskExecutor, ali još uvijek ne želimo njegovo trčanje metoda koja će se izvršiti tijekom našeg testa. Pa, pogledajmo zadnji odjeljak koji objašnjava kako to možemo postići.

6. Prevencija ako ne dignete cijelu posudu

Ovdje ćemo opisati kako možemo spriječiti CommandLineTaskExecutor i ApplicationRunnerTaskExecutor grah iz izvršenja ne pokretanjem cijelog spremnika aplikacije.

U prethodnim odjeljcima koristili smo @SpringBootTest i to je rezultiralo podizanjem cijelog spremnika tijekom naših integracijskih testova. @SpringBootTest uključuje dvije meta-bilješke koje su relevantne za ovo posljednje rješenje:

@BootstrapWith (SpringBootTestContextBootstrapper.class) @ExtendWith (SpringExtension.class) 

Pa, ako nema potrebe za pokretanjem cijelog spremnika tijekom našeg testa, onda ne želite koristiti @BootstrapWith.

Umjesto toga, možemo ga zamijeniti s @ContextConfiguration:

@ContextConfiguration (klase = {ApplicationCommandLineRunnerApp.class}, inicijalizatori = ConfigFileApplicationContextInitializer.class)

S @ContextConfiguration, određujemo kako učitati i konfigurirati kontekst aplikacije za integracijske testove. Postavljanjem ContextConfiguration razreda svojstvo, izjavljujemo da bi Spring Boot trebao koristiti ApplicationCommandLineRunnerApp klasa za učitavanje konteksta aplikacije. Definiranjem inicijalizatora kao ConfigFileApplicationContextInitializer, aplikacija učitava svoja svojstva.

Još uvijek trebamo@ExtendWith (SpringExtension.class) budući da to integrira Spring TestContext Framework u JUnit 5-ov Jupiterov model programiranja.

Kao rezultat gore navedenog, kontekst aplikacije Spring Boot učitava komponente i svojstva aplikacije bez izvršavanja datoteke CommandLineTaskExecutor ili ApplicationRunnerTaskExecutor grah:

@ExtendWith (SpringExtension.class) @ContextConfiguration (klase = {ApplicationCommandLineRunnerApp.class}, inicijalizatori = ConfigFileApplicationContextInitializer.class) javna klasa LoadSpringContextIntegrationTest {@SpyBean TaskService; @SpyBean CommandLineRunner commandLineRunner; @SpyBean ApplicationRunner applicationRunner; @Test void whenContextLoads_thenRunnersDoNotRun () baca iznimku {assertNotNull (taskService); assertNotNull (commandLineRunner); assertNotNull (applicationRunner); verify (taskService, puta (0)). execute (any ()); verify (commandLineRunner, puta (0)). run (any ()); verify (applicationRunner, puta (0)). run (any ()); }} 

Također, moramo to imati na umu the ConfigFileApplicationContextInitializer, kada se koristi sam, ne pruža podršku za @Vrijednost (“$ {…}”) injekcija. Ako ga želimo podržati, moramo konfigurirati a PropertySourcesPlaceholderConfigurer.

7. Zaključak

U ovom smo članku prikazali razne načine sprečavanja izvršenja ApplicationRunner i CommandLineRunner grah tijekom Spring Boot integracijskih testova.

Kao i uvijek, kôd je dostupan na GitHub-u.