מנע מביצוע של פולי ApplicationRunner או CommandLineRunner במהלך בדיקת Junit

1. סקירה כללית

במדריך זה נראה כיצד אנו יכולים למנוע שעועית מסוג ApplicationRunner אוֹ CommandLineRunner מריצה במהלך מבחני שילוב האביב.

2. יישום לדוגמא

יישום הדוגמה שלנו מורכב מרץ שורת פקודה, רץ יישומים ושעועית שירות משימות.

רץ שורת הפקודה, מתקשר לשירות המשימות לבצע שיטה, על מנת לבצע משימה בהפעלת היישום:

המחלקה הציבורית @Component CommandLineTaskExecutor מיישמת את CommandLineRunner {TaskService taskService הפרטי; ציבור CommandLineTaskExecutor (TaskService taskService) {this.taskService = taskService; } ריצה בטלנית ציבורית של @Override (String ... args) זורקת Exception {taskService.execute ("משימת רץ בשורת הפקודה"); }} 

באותו אופן, רץ היישומים מתקשר עם שירות המשימות כדי לבצע משימה אחרת:

מחלקה ציבורית @Component ApplicationRunnerTaskExecutor מיישמת את ApplicationRunner {private TaskService taskService; ApplicationRunnerTaskExecutor ציבורי (TaskService taskService) {this.taskService = taskService; } @Override הפעלה בטלנית ציבורית (ApplicationArguments args) זורקת Exception {taskService.execute ("משימת רץ היישום"); }} 

לבסוף, שירות המשימות אחראי על ביצוע משימות הלקוח שלו:

מחלקה ציבורית @Service TaskService {לוגר לוגר סטטי פרטי = LoggerFactory.getLogger (TaskService.class); ביצוע חלל ציבורי (משימה מחרוזת) {logger.info ("לעשות" + משימה); }} 

ויש לנו גם שיעור יישומי Spring Boot שגורם לכל לעבוד:

@SpringBootApplication מחלקה ציבורית ApplicationCommandLineRunnerApp {main static public void (String [] args) {SpringApplication.run (ApplicationCommandLineRunnerApp.class, args); }}

3. בדיקת התנהגות צפויה

ה ApplicationRunnerTaskExecutor וה CommandLineTaskExecutor לרוץ לאחר Spring Boot טוען את הקשר היישום.

אנו יכולים לאמת זאת באמצעות בדיקה פשוטה:

מחלקה @ SpringBootTest RunApplicationIntegrationTest {@SpyBean ApplicationRunnerTaskExecutor applicationRunnerTaskExecutor; @SpyBean CommandLineTaskExecutor commandLineTaskExecutor; @Test בטל כאשרContextLoads_thenRunnersRun () זורק חריג {אמת (applicationRunnerTaskExecutor, פעמים (1)). הפעל (any ()); אמת (commandLineTaskExecutor, פעמים (1)). הפעל (any ()); }}

כפי שאנו רואים, אנו משתמשים ב- SpyBean ביאור להחלת מרגלים Mockito על ApplicationRunnerTaskExecutor ו CommandLineTaskExecutor שעועית. על ידי כך אנו יכולים לוודא שה- לָרוּץ השיטה של ​​כל אחד מהשעועית הללו נקראה פעם אחת.

בסעיפים הבאים אנו הולכים לראות דרכים וטכניקות שונות למניעת התנהגות ברירת מחדל זו במהלך בדיקות שילוב האביב שלנו.

4. מניעה באמצעות פרופילי אביב

אחת הדרכים בהן אנו יכולים למנוע מהשניים האלה לפעול היא על ידי הערת אותם באמצעות @פּרוֹפִיל:

@Profile ("! Test") @Component class class CommandLineTaskExecutor מיישם את CommandLineRunner {// כמו שקודם לכן}
@Profile ("! Test") @Component class class ApplicationRunnerTaskExecutor מיישם את ApplicationRunner {// אותו הדבר כמו קודם}

לאחר השינויים הנ"ל, אנו ממשיכים במבחן האינטגרציה שלנו:

@ActiveProfiles ("test") מחלקה @SpringBootTest RunApplicationWithTestProfileIntegrationTest {@Autowired פרטי ApplicationContext הקשר; @Test בטל כאשרContextLoads_thenRunnersAreNotLoaded () {assertNotNull (context.getBean (TaskService.class)); assertThrows (NoSuchBeanDefinitionException.class, () -> context.getBean (CommandLineTaskExecutor.class), "אסור לטעון את CommandLineRunner במהלך מבחן האינטגרציה הזה"); assertThrows (NoSuchBeanDefinitionException.class, () -> context.getBean (ApplicationRunnerTaskExecutor.class), "אין לטעון את ApplicationRunner במהלך מבחן האינטגרציה הזה"); }}

כפי שאנו רואים, הערנו את שיעור המבחנים הנ"ל עם ה- @ActiveProfiles ("מבחן") ביאור, מה שאומר שהוא לא יחבר את אלה שמסומנים @Profile ("! Test"). כתוצאה מכך, גם לא CommandLineTaskExecutor שעועית וגם לא ApplicationRunnerTaskExecutor שעועית טעונה בכלל.

5. מניעה באמצעות ConditionalOnProperty ביאור

לחלופין, אנו יכולים להגדיר את החיווט שלהם לפי רכוש ואז להשתמש ב- ConditionalOnProperty ביאור:

@ConditionalOnProperty (קידומת = "application.runner", value = "מופעלת", havingValue = "true", matchIfMissing = true) @Component מחלקה ציבורית ApplicationRunnerTaskExecutor מיישם את ApplicationRunner {// כמו פעם} 
@ConditionalOnProperty (קידומת = "command.line.runner", value = "מופעל", havingValue = "true", matchIfMissing = true) @Component מחלקה ציבורית CommandLineTaskExecutor מיישם את CommandLineRunner {// כמו פעם}

כפי שאנו רואים, ה ApplicationRunnerTaskExecutor וה CommandLineTaskExecutor מופעלים כברירת מחדל, ונוכל להשבית אותם אם נגדיר את המאפיינים הבאים ל- שֶׁקֶר:

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

אז במבחן שלנו, הגדרנו את המאפיינים האלה ל- שֶׁקֶר וגם לא ApplicationRunnerTaskExecutor וגם לא CommandLineTaskExecutor שעועית נטענת להקשר היישום:

@SpringBootTest (מאפיינים = {"command.line.runner.enabled = false", "application.runner.enabled = false"}) מחלקה RunApplicationWithTestPropertiesIntegrationTest {// זהה לפעם}

כעת, למרות שהטכניקות שלעיל עוזרות לנו להשיג את מטרתנו, ישנם מקרים בהם אנו רוצים לבדוק שכל שעועית הקפיץ טעונה וחיווט נכון.

לדוגמה, ייתכן שנרצה לבדוק את ה- TaskService השעועית מוזרקת כהלכה CommandLineTaskExecutor, אבל אנחנו עדיין לא רוצים את זה לָרוּץ שיטה שתבוצע במהלך הבדיקה שלנו. אז בואו נראה את החלק האחרון שמסביר כיצד נוכל להשיג זאת.

6. מניעה על ידי אי אתחול המכל כולו

כאן נתאר כיצד נוכל למנוע את CommandLineTaskExecutor ו ApplicationRunnerTaskExecutor שעועית מהביצוע על ידי אי אתחול כל מיכל היישום.

בסעיפים הקודמים השתמשנו ב- @ SpringBootTest ההערה והביאה לכך שהמיכל כולו יופעל במהלך בדיקות האינטגרציה שלנו. @ SpringBootTest כולל שתי מטא-ביאורים הרלוונטיים לפיתרון האחרון הזה:

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

ובכן, אם אין צורך לאתחל את המכולה כולה במהלך הבדיקה שלנו, אז אל תרצה להשתמש בה @BootstrapWith.

במקום זאת, אנחנו יכולים להחליף את זה ב @ContextConfiguration:

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

עם @ContextConfiguration, אנו קובעים כיצד לטעון ולהגדיר את הקשר היישום לבדיקות אינטגרציה. על ידי הגדרת ה- ContextConfiguration שיעורים נכס, אנו מצהירים כי Spring Boot צריך להשתמש ב- ApplicationCommandLineRunnerApp בכיתה לטעינת הקשר היישום. על ידי הגדרת האתחול להיות ה- ConfigFileApplicationContextInitializer, היישום טוען את המאפיינים שלו.

אנחנו עדיין צריכים@ExtendWith (SpringExtension.class) מכיוון שזו משלבת את Spring TestContext Framework במודל התכנות Jupiter 5 של JUnit.

כתוצאה מהאמור לעיל, ההקשר של היישום Spring Boot טוען את רכיבי היישום ותכונותיו מבלי לבצע את CommandLineTaskExecutor או ה ApplicationRunnerTaskExecutor שעועית:

@ExtendWith (SpringExtension.class) @ContextConfiguration (classes = {ApplicationCommandLineRunnerApp.class}, initializers = ConfigFileApplicationContextInitializer.class) class public LoadSpringContextIntegrationTest {@SpyBean TaskService taskService; @SpyBean CommandLineRunner commandLineRunner; @SpyBean ApplicationRunner applicationRunner; @Test בטל כאשרContextLoads_thenRunnersDoNotRun () זורק Exception {assertNotNull (taskService); assertNotNull (commandLineRunner); assertNotNull (applicationRunner); אמת (taskService, זמנים (0)). execute (any ()); אמת (commandLineRunner, times (0)). run (any ()); אמת (applicationRunner, times (0)). run (any ()); }} 

כמו כן, עלינו לזכור זאת ה ConfigFileApplicationContextInitializer, כאשר משתמשים בו לבד, אינו מספק תמיכה ב @Value ("$ {...}") זריקה. אם אנחנו רוצים לתמוך בזה עלינו להגדיר א PropertySourcesPlaceholderConfigurer.

7. מסקנה

במאמר זה, הראינו דרכים שונות למניעת ביצוע ה- ApplicationRunner ו CommandLineRunner שעועית במהלך מבחני שילוב האביב.

כמו תמיד, הקוד זמין ב- GitHub.