Forhindre at ApplicationRunner eller CommandLineRunner Beans kjøres under Junit-testing

1. Oversikt

I denne opplæringen viser vi hvordan vi kan forhindre bønner av typen ApplicationRunner eller CommandLineRunner fra å kjøre under Spring Boot-integrasjonstester.

2. Eksempel på applikasjon

Eksempelprogrammet vårt består av en kommandolinjeløper, en applikasjonsløper og en oppgavetjeneste.

Kommandolinjeløperen, kaller oppgavetjenesten henrette metode for å utføre en oppgave ved oppstart av applikasjonen:

@Component public class CommandLineTaskExecutor implementerer CommandLineRunner {private TaskService taskService; offentlig CommandLineTaskExecutor (TaskService taskService) {this.taskService = taskService; } @ Override public void run (String ... args) kaster Unntak {taskService.execute ("kommandolinjeløperoppgave"); }} 

På samme måte samhandler applikasjonsløperen med oppgavetjenesten for å utføre en annen oppgave:

@Komponent offentlig klasse ApplicationRunnerTaskExecutor implementerer ApplicationRunner {private TaskService taskService; offentlig ApplicationRunnerTaskExecutor (TaskService taskService) {this.taskService = taskService; } @Override public void run (ApplicationArguments args) kaster Unntak {taskService.execute ("application runner task"); }} 

Til slutt er oppgavetjenesten ansvarlig for å utføre klientens oppgaver:

@Service offentlig klasse TaskService {privat statisk loggerlogger = LoggerFactory.getLogger (TaskService.class); offentlig tomrom utføre (strengoppgave) {logger.info ("gjør" + oppgave); }} 

Og vi har også en Spring Boot-applikasjonsklasse som gjør at alt fungerer:

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

3. Testing av forventet atferd

De ApplicationRunnerTaskExecutor og CommandLineTaskExecutor kjør etter at Spring Boot laster applikasjonskonteksten.

Vi kan bekrefte dette med en enkel test:

@SpringBootTest klasse RunApplicationIntegrationTest {@SpyBean ApplicationRunnerTaskExecutor applicationRunnerTaskExecutor; @SpyBean CommandLineTaskExecutor commandLineTaskExecutor; @Test ugyldig nårContextLoads_thenRunnersRun () kaster Unntak {verifiser (applicationRunnerTaskExecutor, times (1)). Run (any ()); verifiser (commandLineTaskExecutor, times (1)). run (any ()); }}

Som vi ser bruker vi SpyBean kommentar for å bruke Mockito spioner på ApplicationRunnerTaskExecutor og CommandLineTaskExecutor bønner. Ved å gjøre det kan vi bekrefte at løpe metoden for hver av disse bønnene ble kalt en gang.

I de neste avsnittene skal vi se forskjellige måter og teknikker for å forhindre denne standardadferden under vår Spring Boot-integrasjonstester.

4. Forebygging via vårprofiler

En måte vi kan forhindre at disse to kjører på er å kommentere dem med @Profil:

@Profile ("! Test") @Component public class CommandLineTaskExecutor implementerer CommandLineRunner {// samme som før}
@Profile ("! Test") @Komponent offentlig klasse ApplicationRunnerTaskExecutor implementerer ApplicationRunner {// samme som før}

Etter endringene ovenfor fortsetter vi med integrasjonstesten:

@ActiveProfiles ("test") @SpringBootTest klasse RunApplicationWithTestProfileIntegrationTest {@Autowired private ApplicationContext context; @Test ugyldig nårContextLoads_thenRunnersAreNotLoaded () {assertNotNull (context.getBean (TaskService.class)); assertThrows (NoSuchBeanDefinitionException.class, () -> context.getBean (CommandLineTaskExecutor.class), "CommandLineRunner skal ikke lastes under denne integrasjonstesten"); assertThrows (NoSuchBeanDefinitionException.class, () -> context.getBean (ApplicationRunnerTaskExecutor.class), "ApplicationRunner bør ikke lastes under denne integrasjonstesten"); }}

Som vi ser, vi kommenterte testklassen ovenfor med @ActiveProfiles (“test”) kommentar, noe som betyr at den ikke vil overføre dem som er merket med @Profile (“! Test”). Som et resultat, verken CommandLineTaskExecutor bønne eller ApplicationRunnerTaskExecutor bønne er lastet i det hele tatt.

5. Forebygging via ConditionalOnProperty Kommentar

Eller vi kan konfigurere ledningene deres etter eiendom og deretter bruke ConditionalOnProperty kommentar:

@ConditionalOnProperty (prefiks = "application.runner", value = "enabled", havingValue = "true", matchIfMissing = true) @Component public class ApplicationRunnerTaskExecutor implementerer ApplicationRunner {// samme som før} 
@ConditionalOnProperty (prefiks = "command.line.runner", value = "enabled", havingValue = "true", matchIfMissing = true) @Component public class CommandLineTaskExecutor implementerer CommandLineRunner {// samme som før}

Som vi ser, de ApplicationRunnerTaskExecutor og CommandLineTaskExecutor er aktivert som standard, og vi kan deaktivere dem hvis vi setter følgende egenskaper til falsk:

  • command.line.runner.enabled
  • application.runner.enabled

Så i vår test, vi setter disse egenskapene til falsk og verken ApplicationRunnerTaskExecutor ei heller CommandLineTaskExecutor bønner lastes inn i applikasjonskonteksten:

@SpringBootTest (egenskaper = {"command.line.runner.enabled = false", "application.runner.enabled = false"}) klasse RunApplicationWithTestPropertiesIntegrationTest {// samme som før}

Nå, selv om ovennevnte teknikker hjelper oss med å nå vårt mål, er det tilfeller der vi vil teste at alle vårbønnene er lastet og kablet riktig.

For eksempel kan det være lurt å teste at TaskService bønnen injiseres riktig i CommandLineTaskExecutor, men vi vil fortsatt ikke ha det løpe metoden som skal utføres under testen. Så, la oss se den siste delen som forklarer hvordan vi kan oppnå det.

6. Forebygging ved å ikke starte hele beholderen

Her vil vi beskrive hvordan vi kan forhindre CommandLineTaskExecutor og ApplicationRunnerTaskExecutor bønner fra utførelse ved ikke å starte hele applikasjonsbeholderen.

I de forrige avsnittene brukte vi @SpringBootTest kommentar og dette resulterte i at hele containeren ble startet opp under integrasjonstestene våre. @SpringBootTest inneholder to metaanmerkninger som er relevante for denne siste løsningen:

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

Vel, hvis det ikke er behov for å starte hele beholderen under testen, vil du ikke bruke den @BootstrapWith.

I stedet, vi kan erstatte den med @ContextConfiguration:

@ContextConfiguration (klasser = {ApplicationCommandLineRunnerApp.class}, initializers = ConfigFileApplicationContextInitializer.class)

Med @ContextConfiguration, vi bestemmer hvordan du skal laste inn og konfigurere applikasjonskonteksten for integrasjonstester. Ved å stille inn Kontekstkonfigurasjon klasser eiendom erklærer vi at Spring Boot skal bruke ApplicationCommandLineRunnerApp klasse for å laste applikasjonskonteksten. Ved å definere initialisereren som ConfigFileApplicationContextInitializer, applikasjonen laster inn egenskapene.

Vi trenger fremdeles@ExtendWith (SpringExtension.class) siden det integrerer Spring TestContext Framework i JUnit 5s Jupiter programmeringsmodell.

Som et resultat av ovenstående, Spring Boot-applikasjonskonteksten laster programmets komponenter og egenskaper uten å utføre CommandLineTaskExecutor eller ApplicationRunnerTaskExecutor bønner:

@ExtendWith (SpringExtension.class) @ContextConfiguration (classes = {ApplicationCommandLineRunnerApp.class}, initializers = ConfigFileApplicationContextInitializer.class) public class LoadSpringContextIntegrationTest {@SpyBean TaskService taskService; @SpyBean CommandLineRunner commandLineRunner; @SpyBean ApplicationRunner applicationRunner; @Test ugyldig nårContextLoads_thenRunnersDoNotRun () kaster Unntak {assertNotNull (taskService); assertNotNull (commandLineRunner); assertNotNull (applicationRunner); verifisere (taskService, times (0)). execute (any ()); verifiser (commandLineRunner, times (0)). run (any ()); verifisere (applicationRunner, times (0)). run (any ()); }} 

Vi må også huske på det de ConfigFileApplicationContextInitializer, når den brukes alene, gir ikke støtte for @Value (“$ {...}”) injeksjon. Hvis vi vil støtte det, må vi konfigurere en PropertySourcesPlaceholderConfigurer.

7. Konklusjon

I denne artikkelen viste vi forskjellige måter å forhindre utførelsen av ApplicationRunner og CommandLineRunner bønner under Spring Boot-integrasjonstester.

Som alltid er koden tilgjengelig på GitHub.


$config[zx-auto] not found$config[zx-overlay] not found