בדיקת עבודת אצווה באביב

1. הקדמה

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

במדריך זה נבחן את החלופות השונות לבדיקת עבודת באביב באץ '.

2. תלות נדרשת

אנחנו משתמשים אביב-אתחול-המתנע-אצווהאז ראשית בואו נקבע את התלות הנדרשת בתוכנו pom.xml:

 org.springframework.boot spring-boot-starter-batch 2.1.9.RELEASE org.springframework.boot spring-boot-starter-test 2.1.9.RELEASE test org.springframework.batch spring-batch-test 4.2.0.RELEASE מִבְחָן 

כללנו את אביב-בומבחן t-starter ו אביב-אצווה-מבחן אשר מביאים כמה שיטות עוזר נחוצות, מאזינים ורצים לבדיקת יישומי Spring Batch.

3. הגדרת עבודת אצווה באביב

בוא ניצור יישום פשוט כדי להראות כיצד Spring Batch פותר חלק מאתגרי הבדיקה.

היישום שלנו משתמש בשני שלבים עבודה שקורא קובץ קלט CSV עם מידע מובנה על ספרים ומוציא ספרים ופרטי ספרים.

3.1. הגדרת שלבי העבודה

השניים הבאים שלבs לחלץ מידע ספציפי מ BookRecordואז למפות את אלה אל סֵפֶרs (שלב 1) ו- BookDetails (שלב 2):

שלב שלב 1 @Bean הציבורי (ItemReader csvItemReader, ItemWriter jsonItemWriter) זורק את IOException {return stepBuilderFactory .get ("step1"). chunk (3) .reader (csvItemReader) .processor (bookItemProcessor ()) .writer (jsonItemWriter) .build (); } @Bean Public Step Step2 (ItemReader csvItemReader, ItemWriter listItemWriter) {החזר stepBuilderFactory .get ("step2"). נתח (3) .reader (csvItemReader). מעבד (bookDetailsItemProcessor ()) .writer (listItemWriter) .build (); }

3.2. הגדרת קורא הקלט וכותב הפלט

בואו עכשיו להגדיר את קורא הקלט לקובץ CSV באמצעות FlatFileItemReader להסיר סדרת מידע מובנה של הספרים BookRecord חפצים:

סופי סטטי פרטי מחרוזת [] TOKENS = {"שם ספר", "מחבר ספרים", "פורמט ספרים", "isbn", "שנת הוצאה"}; @Bean @StepScope FlatFileItemReader ציבורי csvItemReader (@Value ("# {jobParameters ['file.input']}") קלט מחרוזת) {FlatFileItemReaderBuilder בונה = FlatFileItemReaderBuilder חדש (); FieldSetMapper bookRecordFieldSetMapper = BookRecordFieldSetMapper חדש (); בונה החזרה .name ("bookRecordItemReader") .resource (FileSystemResource חדש (קלט)) .בדידה מוגבלת (). names (TOKENS) .fieldSetMapper (bookRecordFieldSetMapper) .build (); }

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

ראשית כל, הערנו את FlatItemReader שעועית עם @StepScope, וכתוצאה, אובייקט זה ישתף את חייו ביצוע שלב.

זה גם מאפשר לנו להזרים ערכים דינמיים בזמן ריצה, כך שנוכל להעביר את קובץ הקלט שלנו מה- JobParameterבשורה 4. לעומת זאת, האסימונים המשמשים ל BookRecordFieldSetMapper מוגדרים בזמן הידור.

לאחר מכן אנו מגדירים באופן דומה את JsonFileItemWriter כותב פלט:

@Bean @StepScope JsonFileItemWriter הציבורי jsonItemWriter (@Value ("# {jobParameters ['file.output']}") פלט מחרוזת) זורק IOException {JsonFileItemWriterBuilder בונה = JsonFileItemWriterBuilder חדש); JacksonJsonObjectMarshaller marshaller = חדש JacksonJsonObjectMarshaller (); בונה החזרת .name ("bookItemWriter") .jsonObjectMarshaller (marshaller) .resource (FileSystemResource חדש (פלט)) .build (); } 

לשנייה שלב, אנו משתמשים באספקת Spring Batch ListItemWriter שפשוט משליך דברים לרשימה בזיכרון.

3.3. הגדרת המותאם אישית JobLauncher

לאחר מכן, בואו נשבית את ברירת המחדל עבודה השקת תצורה של Spring Boot Batch על ידי הגדרה spring.batch.job.enabled = שקר בשלנו application.properties.

אנו מגדירים את עצמנו JobLauncher להעביר מנהג JobParameters למשל כאשר משיקים את עבודה:

@SpringBootApplication המחלקה הציבורית SpringBatchApplication מיישמת את CommandLineRunner {// jobWauncher אוטומטית ו transformBooksRecordsJob @Value ("$ {file.input}") קלט מחרוזת פרטי; @Value ("$ {file.output}") פלט מחרוזת פרטי; @Override הפעלה בטלנית ציבורית (String ... args) זורקת Exception {JobParametersBuilder paramsBuilder = JobParametersBuilder חדש (); paramsBuilder.addString ("file.input", קלט); paramsBuilder.addString ("file.output", פלט); jobLauncher.run (transformBooksRecordsJob, paramsBuilder.toJobParameters ()); } // שיטות אחרות (ראשי וכו ')} 

4. בדיקת עבודת אצווה באביב

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

בואו ניצור מבנה בסיסי למבחן שלנו:

@RunWith (SpringRunner.class) @SpringBatchTest @EnableAutoConfiguration @ContextConfiguration (class = {SpringBatchConfiguration.class}) @TestExecutionListeners ({DependencyInjectionTestExecutionListener.class, DirtiesContextTestExecutionListener.ass) ClasseTimeClass_Manager_Class_Manager_Time_ContextTestExecutionListener. קבועי בדיקה אחרים @ JobLauncherTestUtils פרטיים אוטומטיים JobLauncherTestUtils; @Autowired פרטי JobRepositoryTestUtils jobRepositoryTestUtils; @ לאחר הריק פומבי cleanUp () {jobRepositoryTestUtils.removeJobExecutions (); } JobParameters פרטיים defaultJobParameters () {JobParametersBuilder paramsBuilder = JobParametersBuilder חדש (); paramsBuilder.addString ("file.input", TEST_INPUT); paramsBuilder.addString ("file.output", TEST_OUTPUT); להחזיר paramsBuilder.toJobParameters (); } 

ה @ SpringBatchTest ההערה מספקת את JobLauncherTestUtils ו JobRepositoryTestUtils שיעורי עוזר. אנו משתמשים בהם כדי להפעיל את עבודה ו שלבבמבחנים שלנו.

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

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

4.1. בדיקת הקצה לקצה עבודה

הדבר הראשון שנבדוק הוא קצה לקצה שלם עבודה עם קלט מערך נתונים קטן.

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

@Test ציבורי בטל givenReferenceOutput_whenJobExecuted_thenSuccess () זורק חריג {// נתון FileSystemResource expectResult = FileSystemResource חדש (EXPECTED_OUTPUT); FileSystemResource actualResult = FileSystemResource חדש (TEST_OUTPUT); // כאשר JobExecution jobExecution = jobLauncherTestUtils.launchJob (defaultJobParameters ()); JobInstance actualJobInstance = jobExecution.getJobInstance (); ExitStatus actualJobExitStatus = jobExecution.getExitStatus (); // ואז assertThat (actualJobInstance.getJobName (), הוא ("transformBooksRecords")); assertThat (actualJobExitStatus.getExitCode (), הוא ("הושלם")); AssertFile.assertFileEquals (expectResult, actualResult); }

מבחן אצווה באביב מספק מועיל שיטת השוואת קבצים לאימות תפוקות באמצעות AssertFile מעמד.

4.2. בדיקת צעדים בודדים

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

@Test הציבורי בטל givenReferenceOutput_whenStep1Executed_thenSuccess () זורק חריג {// נתון FileSystemResource expectResult = FileSystemResource חדש (EXPECTED_OUTPUT); FileSystemResource actualResult = FileSystemResource חדש (TEST_OUTPUT); // כאשר JobExecution jobExecution = jobLauncherTestUtils.launchStep ("step1", defaultJobParameters ()); אוסף actualStepExecutions = jobExecution.getStepExecutions (); ExitStatus actualJobExitStatus = jobExecution.getExitStatus (); // ואז assertThat (actualStepExecutions.size (), הוא (1)); assertThat (actualJobExitStatus.getExitCode (), הוא ("הושלם")); AssertFile.assertFileEquals (expectResult, actualResult); } @Test ציבורי בטל כאשר Step2Executed_thenSuccess () {// כאשר JobExecution jobExecution = jobLauncherTestUtils.launchStep ("step2", defaultJobParameters ()); אוסף actualStepExecutions = jobExecution.getStepExecutions (); ExitStatus actualExitStatus = jobExecution.getExitStatus (); // ואז assertThat (actualStepExecutions.size (), הוא (1)); assertThat (actualExitStatus.getExitCode (), הוא ("הושלם")); actualStepExecutions.forEach (stepExecution -> {assertThat (stepExecution.getWriteCount (), הוא (8));}); }

שים לב ש אנו משתמשים ב- launchStep שיטה להפעלת צעדים ספציפיים.

זכור את זה תכננו גם את שלנו ItemReader ו ItemWriter להשתמש בערכים דינמיים בזמן ריצה, אשר אומר אנו יכולים להעביר את פרמטרי ה- I / O שלנו ל- ביצוע עבודה(שורות 9 ו -23).

לראשונה שלב בדיקה, אנו משווים את התפוקה בפועל עם התפוקה הצפויה.

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

4.3. בדיקת רכיבים מדורגים

בואו עכשיו נבדוק את FlatFileItemReader. נזכיר שחשפנו את זה כ @StepScope שעועית, אז נרצה להשתמש בתמיכה הייעודית של Spring Batch לכך:

// פריט אוטומטי של חוויית אוטומטי Reader @Test פומבי givenMockedStep_whenReaderCalled_thenSuccess () זורק חריג {// נתון StepExecution stepExecution = MetaDataInstanceFactory .createStepExecution (defaultJobParameters ()); // כאשר StepScopeTestUtils.doInStepScope (stepExecution, () -> {BookRecord bookRecord; itemReader.open (stepExecution.getExecutionContext ()); while ((bookRecord = itemReader.read ())! = null) {// ואז assertThat (bookRecord .getBookName (), הוא ("קרן")); assertThat (bookRecord.getBookAuthor (), הוא ("Asimov I.")); assertThat (bookRecord.getBookISBN (), הוא ("ISBN 12839")); assertThat ( bookRecord.getBookFormat (), הוא ("כריכה קשה")); assertThat (bookRecord.getPublishingYear (), הוא ("2018"));} itemReader.close (); להחזיר null;}); }

ה MetadataInstanceFactory יוצר מנהג ביצוע שלב שצריך כדי להזריק את ה- Step-scoped שלנו ItemReader.

בגלל זה, אנו יכולים לבדוק את התנהגות הקורא בעזרת ה- doInTestScope שיטה.

הבא, בואו נבדוק את JsonFileItemWriter ואמת את תפוקתו:

@Test הציבור בטל givenMockedStep_whenWriterCalled_thenSuccess () זורק חריג {// נתון FileSystemResource expectResult = FileSystemResource חדש (EXPECTED_OUTPUT_ONE); FileSystemResource actualResult = FileSystemResource חדש (TEST_OUTPUT); ספר ספר demo = ספר חדש (); demoBook.setAuthor ("גרישם ג'יי"); demoBook.setName ("המשרד"); StepExecution stepExecution = MetaDataInstanceFactory .createStepExecution (defaultJobParameters ()); // כאשר StepScopeTestUtils.doInStepScope (stepExecution, () -> {jsonItemWriter.open (stepExecution.getExecutionContext ()); jsonItemWriter.write (Arrays.asList (demoBook)); jsonItemWriter.close (); return null;}); // ואז AssertFile.assertFileEquals (expectResult, actualResult); } 

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

5. מסקנה

במדריך זה חקרנו את הגישות השונות לבדיקת עבודת אצווה באביב.

בדיקה מקצה לקצה מאמתת את ביצוע העבודה המלא. בדיקת צעדים בודדים עשויה לעזור בתרחישים מורכבים.

לבסוף, כשמדובר ברכיבים המומלצים ב- Step, אנו יכולים להשתמש בחבורת שיטות עוזרות המסופקות על ידי אביב-אצווה-מבחן. הם יסייעו לנו לדקור וללעוג לאובייקטים של תחומי Spring Batch.

כרגיל, אנו יכולים לחקור את בסיס הקוד המלא ב- GitHub.


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