Undgå, at ApplicationRunner eller CommandLineRunner Beans udføres under Junit-test

1. Oversigt

I denne vejledning viser vi, hvordan vi kan forhindre bønner af typen ApplicationRunner eller CommandLineRunner fra at køre under Spring Boot-integrationstest.

2. Eksempel på anvendelse

Vores eksempelapplikation består af en kommandolinjeløber, en applikationsløber og en task service bønne.

Kommandolinjeløberen kalder opgavetjenestens udføre metode for at udføre en opgave ved opstart af applikationen:

@Komponent offentlig klasse CommandLineTaskExecutor implementerer CommandLineRunner {privat TaskService taskService; offentlig CommandLineTaskExecutor (TaskService taskService) {this.taskService = taskService; } @ Override public void run (String ... args) kaster Undtagelse {taskService.execute ("kommandolinjeløberopgave"); }} 

På samme måde interagerer applikationsløberen med opgavetjenesten for at udføre en anden opgave:

@Komponent offentlig klasse ApplicationRunnerTaskExecutor implementerer ApplicationRunner {private TaskService taskService; offentlig ApplicationRunnerTaskExecutor (TaskService taskService) {this.taskService = taskService; } @Override public void run (ApplicationArguments args) kaster Undtagelse {taskService.execute ("applikationsløberopgave"); }} 

Endelig er opgavetjenesten ansvarlig for at udføre klientens opgaver:

@Service offentlig klasse TaskService {privat statisk loggerlogger = LoggerFactory.getLogger (TaskService.class); offentlig ugyldig udførelse (strengopgave) {logger.info ("gør" + opgave); }} 

Og vi har også en Spring Boot-applikationsklasse, der får det hele til at fungere:

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

3. Test af forventet adfærd

Det ApplicationRunnerTaskExecutor og CommandLineTaskExecutor kør efter Spring Boot indlæser applikationskonteksten.

Vi kan bekræfte dette med en simpel test:

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

Som vi ser bruger vi SpyBean kommentar for at anvende Mockito spioner på ApplicationRunnerTaskExecutor og CommandLineTaskExecutor bønner. Ved at gøre dette kan vi kontrollere, at løb metode til hver af disse bønner blev kaldt en gang.

I de næste sektioner vil vi se forskellige måder og teknikker til at forhindre denne standardadfærd under vores Spring Boot-integrationstests.

4. Forebyggelse via forårsprofiler

En måde, hvorpå vi kan forhindre disse to i at køre, er ved at 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}

Efter ovenstående ændringer fortsætter vi med vores integrationstest:

@ActiveProfiles ("test") @SpringBootTest klasse RunApplicationWithTestProfileIntegrationTest {@Autowired privat ApplicationContext kontekst; @Test ugyldigt nårContextLoads_thenRunnersAreNotLoaded () {assertNotNull (context.getBean (TaskService.class)); assertThrows (NoSuchBeanDefinitionException.class, () -> context.getBean (CommandLineTaskExecutor.class), "CommandLineRunner bør ikke indlæses under denne integrationstest"); assertThrows (NoSuchBeanDefinitionException.class, () -> context.getBean (ApplicationRunnerTaskExecutor.class), "ApplicationRunner skal ikke indlæses under denne integrationstest"); }}

Som vi ser, vi kommenterede ovenstående testklasse med @ActiveProfiles (“test”) kommentar, hvilket betyder, at den ikke vil overføre dem, der er kommenteret med @Profile (“! Test”). Som et resultat, hverken CommandLineTaskExecutor bønne eller ApplicationRunnerTaskExecutor bønne er overhovedet fyldt.

5. Forebyggelse via ConditionalOnProperty Kommentar

Eller vi kan konfigurere deres ledninger efter ejendom og derefter bruge ConditionalOnProperty kommentar:

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

Som vi ser, det ApplicationRunnerTaskExecutor og CommandLineTaskExecutor er aktiveret som standard, og vi kan deaktivere dem, hvis vi indstiller følgende egenskaber til falsk:

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

Så i vores test, vi indstiller disse egenskaber til falsk og hverken den ApplicationRunnerTaskExecutor ej heller CommandLineTaskExecutor bønner indlæses i applikationskonteksten:

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

Nu, selvom ovennævnte teknikker hjælper os med at nå vores mål, er der tilfælde, hvor vi vil teste, at alle springbønner er ilagt og kablet korrekt.

For eksempel vil vi måske teste, at TaskService bønnen injiceres korrekt i CommandLineTaskExecutor, men vi vil stadig ikke have det løb metode, der skal udføres under vores test. Så lad os se det sidste afsnit, der forklarer, hvordan vi kan opnå det.

6. Forebyggelse ved ikke at bootstrappe hele beholderen

Her beskriver vi, hvordan vi kan forhindre CommandLineTaskExecutor og ApplicationRunnerTaskExecutor bønner fra udførelse ved ikke at bootstrappe hele applikationsbeholderen.

I de foregående afsnit brugte vi @SpringBootTest kommentar, og dette resulterede i, at hele containeren startes under vores integrationstest. @SpringBootTest inkluderer to meta-annoteringer, der er relevante for denne sidste løsning:

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

Nå, hvis der ikke er behov for at starte hele containeren under vores test, så vil du ikke bruge den @BootstrapWith.

I stedet, vi kan erstatte det med @ContextConfiguration:

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

Med @ContextConfiguration, vi bestemmer, hvordan vi indlæser og konfigurerer applikationskonteksten til integrationstest. Ved at indstille Kontekstkonfiguration klasser ejendom erklærer vi, at Spring Boot skal bruge ApplicationCommandLineRunnerApp klasse for at indlæse applikationskonteksten. Ved at definere initialiseringen til at være ConfigFileApplicationContextInitializer, applikationen indlæser dens egenskaber.

Vi har stadig brug for det@ExtendWith (SpringExtension.class) da det integrerer Spring TestContext Framework i JUnit 5s Jupiter programmeringsmodel.

Som et resultat af ovenstående Spring Boot-applikationskonteksten indlæser applikationens komponenter og egenskaber uden at udføre CommandLineTaskExecutor eller den 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 ugyldigt nårContextLoads_thenRunnersDoNotRun () kaster Undtagelse {assertNotNull (taskService); assertNotNull (commandLineRunner); assertNotNull (applicationRunner); verificere (taskService, times (0)). execute (any ()); verificere (commandLineRunner, times (0)). run (any ()); verificer (applicationRunner, times (0)). run (any ()); }} 

Vi skal også huske det det ConfigFileApplicationContextInitializer, når det bruges alene, giver ikke support til @Value (“$ {...}”) indsprøjtning. Hvis vi vil støtte det, er vi nødt til at konfigurere en PropertySourcesPlaceholderConfigurer.

7. Konklusion

I denne artikel viste vi forskellige måder at forhindre udførelsen af ApplicationRunner og CommandLineRunner bønner under Spring Boot-integrationstest.

Som altid er koden tilgængelig på GitHub.


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