Testovanie jarnej dávkovej úlohy

1. Úvod

Na rozdiel od iných jarných aplikácií prichádza testovanie dávkových úloh s niektorými konkrétnymi výzvami, väčšinou kvôli asynchrónnej povahe spôsobu vykonávania úloh.

V tomto výučbe sa chystáme preskúmať rôzne alternatívy testovania úlohy Spring Batch.

2. Požadované závislosti

Používame jar-topánka-štartér-dávka, tak si najskôr nastavíme požadované závislosti v našom 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 test 

Zaradili sme jar-boot-štartovací test a jarný dávkový test ktoré prinášajú niekoľko potrebných pomocných metód, poslucháčov a bežcov na testovanie aplikácií Spring Batch.

3. Definovanie jarnej dávkovej úlohy

Vytvorme si jednoduchú aplikáciu, ktorá ukáže, ako Spring Batch rieši niektoré z testovacích výziev.

Naša aplikácia využíva dva kroky Job ktorý číta vstupný súbor CSV so štruktúrovanými informáciami o knihe a vydáva knihy a podrobnosti knihy.

3.1. Definovanie pracovných krokov

Dva nasledujúce Kroks extrahovať konkrétne informácie z BookRecords a potom ich namapujte na Knihas (krok 1) a BookDetails (krok 2):

@Bean public Krok step1 (ItemReader csvItemReader, ItemWriter jsonItemWriter) vyvolá IOException {return stepBuilderFactory .get ("step1"). chunk (3) .reader (csvItemReader) .processor (bookItemProcessor ()) .writer (jsonItemWriter) .build (); } @Bean public Step step2 (ItemReader csvItemReader, ItemWriter listItemWriter) {return stepBuilderFactory .get ("step2"). chunk (3) .reader (csvItemReader) .processor (bookDetailsItemProcessor ()) .writer (listItemWriter) .build (); }

3.2. Definovanie vstupnej čítačky a výstupnej zapisovateľky

Poďme teraz nakonfigurovať vstupnú čítačku súborov CSV pomocou a FlatFileItemReader na serializáciu štruktúrovaných informácií o knihe BookRecord objekty:

private static final String [] TOKENS = {"bookname", "bookauthor", "bookformat", "isbn", "publishyear"}; @Bean @StepScope public FlatFileItemReader csvItemReader (@Value ("# {jobParameters ['file.input']}") reťazcový vstup) {FlatFileItemReaderBuilder builder = nový FlatFileItemReaderBuilder (); FieldSetMapper bookRecordFieldSetMapper = nový BookRecordFieldSetMapper (); return builder .name ("bookRecordItemReader") .resource (new FileSystemResource (input)) .delimited () .names (TOKENS) .fieldSetMapper (bookRecordFieldSetMapper) .build (); }

V tejto definícii je niekoľko dôležitých vecí, ktoré budú mať dôsledky na spôsob, akým testujeme.

Po prvé, anotovali sme FlatItemReader fazuľa s @StepScope, a ako výsledok, tento objekt bude zdieľať svoju životnosť s StepExecution.

To nám tiež umožňuje vložiť dynamické hodnoty za behu, aby sme mohli odovzdať náš vstupný súbor z JobParameters v riadku 4. Naproti tomu tokeny použité pre BookRecordFieldSetMapper sú nakonfigurované v čase kompilácie.

Potom podobne definujeme JsonFileItemWriter výstupný zapisovač:

@Bean @StepScope public JsonFileItemWriter jsonItemWriter (@Value ("# {jobParameters ['file.output']}") výstup reťazca) vyvolá IOException {JsonFileItemWriterBuilder builder = nový JsonFileItemWriterBuilder (); JacksonJsonObjectMarshaller marshaller = nový JacksonJsonObjectMarshaller (); return builder .name ("bookItemWriter") .jsonObjectMarshaller (marshaller) .resource (new FileSystemResource (output)) .build (); } 

Na druhú Krok, používame jarnú dávku ListItemWriter ktorý jednoducho vypíše veci do zoznamu v pamäti.

3.3. Definovanie zvyku JobLauncher

Ďalej deaktivujeme predvolené nastavenie Job spustenie konfigurácie Spring Boot Batch nastavením spring.batch.job.enabled = false v našom application.properties.

Konfigurujeme si svoje vlastné JobLauncher odovzdať zvyk JobParameters napríklad pri spustení Job:

@SpringBootApplication verejná trieda SpringBatchApplication implementuje CommandLineRunner {// autowired jobLauncher a transformBooksRecordsJob @Value ("$ {file.input}") súkromný vstupný reťazec; @Value ("$ {file.output}") súkromný výstup reťazca; @Override public void run (String ... args) vyvolá výnimku {JobParametersBuilder paramsBuilder = nový JobParametersBuilder (); paramsBuilder.addString ("file.input", vstup); paramsBuilder.addString ("file.output", výstup); jobLauncher.run (transformBooksRecordsJob, paramsBuilder.toJobParameters ()); } // ďalšie metódy (hlavné atď.)} 

4. Testovanie jarnej dávkovej úlohy

The jarný dávkový test Závislosť poskytuje sadu užitočných pomocných metód a poslucháčov, ktoré možno použiť na konfiguráciu kontextu Spring Batch počas testovania.

Vytvorme základnú štruktúru nášho testu:

@RunWith (SpringRunner.class) @SpringBatchTest @EnableAutoConfiguration @ContextConfiguration (classes = {SpringBatchConfiguration.class}) @TestExecutionListeners ({DependencyInjectionTestExecutionListener.class, DirtiesContextTestExecutionList.class} ďalšie testovacie konštanty @Autowired private JobLauncherTestUtils jobLauncherTestUtils; @Autowired private JobRepositoryTestUtils jobRepositoryTestUtils; @After public void cleanUp () {jobRepositoryTestUtils.removeJobExecutions (); } súkromné ​​JobParameters defaultJobParameters () {JobParametersBuilder paramsBuilder = nový JobParametersBuilder (); paramsBuilder.addString ("file.input", TEST_INPUT); paramsBuilder.addString ("file.output", TEST_OUTPUT); vrátiť paramsBuilder.toJobParameters (); } 

The @SpringBatchTest anotácia poskytuje JobLauncherTestUtils a JobRepositoryTestUtils triedy pomocníkov. Používame ich na spustenie Job a Kroks v našich testoch.

Naša aplikácia používa Automatická konfigurácia Spring Boot, ktorá umožňuje predvolenú pamäť JobRepository. Ako výsledok, spustenie viacerých testov v tej istej triede si vyžaduje krok čistenia po každom spustení testu.

Nakoniec ak chceme spustiť viac testov z niekoľkých testovacích tried, musíme náš kontext označiť ako špinavý. Je to potrebné, aby sa zabránilo stretu viacerých osôb JobRepository inštancie používajúce rovnaký zdroj údajov.

4.1. Testovanie typu End-to-End Job

Prvá vec, ktorú otestujeme, je kompletný end-to-end Job s malým vstupom súboru údajov.

Potom môžeme výsledky porovnať s očakávaným výstupom testu:

@Test public void givenReferenceOutput_whenJobExecuted_thenSuccess () vyvolá výnimku {// daný FileSystemResource expectResult = nový FileSystemResource (EXPECTED_OUTPUT); FileSystemResource actualResult = nový FileSystemResource (TEST_OUTPUT); // keď JobExecution jobExecution = jobLauncherTestUtils.launchJob (defaultJobParameters ()); JobInstance actualJobInstance = jobExecution.getJobInstance (); ExitStatus actualJobExitStatus = jobExecution.getExitStatus (); // potom assertThat (actualJobInstance.getJobName (), je ("transformBooksRecords")); assertThat (actualJobExitStatus.getExitCode (), je ("DOKONČENÉ")); AssertFile.assertFileEquals (expectResult, actualResult); }

Spring Batch Test poskytuje užitočné metóda porovnania súborov na overovanie výstupov pomocou AssertFile trieda.

4.2. Testovanie jednotlivých krokov

Niekedy je dosť nákladné otestovať kompletnú verziu Job end-to-end, a preto má zmysel testovať jednotlivca Kroky namiesto toho:

@Test public void givenReferenceOutput_whenStep1Executed_thenSuccess () vyvolá výnimku {// daný FileSystemResource expectResult = nový FileSystemResource (EXPECTED_OUTPUT); FileSystemResource actualResult = nový FileSystemResource (TEST_OUTPUT); // keď JobExecution jobExecution = jobLauncherTestUtils.launchStep ("step1", defaultJobParameters ()); Zbierka actualStepExecutions = jobExecution.getStepExecutions (); ExitStatus actualJobExitStatus = jobExecution.getExitStatus (); // potom assertThat (actualStepExecutions.size (), je (1)); assertThat (actualJobExitStatus.getExitCode (), je ("DOKONČENÉ")); AssertFile.assertFileEquals (expectResult, actualResult); } @Test public void whenStep2Executed_thenSuccess () {// when JobExecution jobExecution = jobLauncherTestUtils.launchStep ("step2", defaultJobParameters ()); Zbierka actualStepExecutions = jobExecution.getStepExecutions (); ExitStatus actualExitStatus = jobExecution.getExitStatus (); // potom assertThat (actualStepExecutions.size (), je (1)); assertThat (actualExitStatus.getExitCode (), je ("DOKONČENÉ")); actualStepExecutions.forEach (stepExecution -> {assertThat (stepExecution.getWriteCount (), je (8));}); }

Všimni si používame launchStep metóda na spustenie konkrétnych krokov.

Zapamätaj si to navrhli sme aj naše ItemReader a ItemWriter používať dynamické hodnoty za behu, čo znamená môžeme odovzdať naše I / O parametre do Vykonanie úlohy(riadky 9 a 23).

Po prvýkrát Krok test, porovnávame skutočný výstup s očakávaným výstupom.

Na druhej strane, v druhom teste overujeme StepExecution za očakávané písomné položky.

4.3. Testovanie komponentov s obmedzeným rozsahom

Poďme teraz otestovať FlatFileItemReader. Pripomeňme, že sme to vystavili ako @StepScope fazuľa, takže na to budeme chcieť využiť špecializovanú podporu Spring Batch:

// predtým autowired itemReader @Test public void givenMockedStep_whenReaderCalled_thenSuccess () vyvolá výnimku {// daný StepExecution stepExecution = MetaDataInstanceFactory .createStepExecution (defaultJobParameters ()); // when StepScopeTestUtils.doInStepScope (stepExecution, () -> {BookRecord bookRecord; itemReader.open (stepExecution.getExecutionContext ()); while ((bookRecord = itemReader.read ())! = null) {// then assertThat (bookRecord .getBookName (), is ("Foundation")); assertThat (bookRecord.getBookAuthor (), is ("Asimov I.")); assertThat (bookRecord.getBookISBN (), is ("ISBN 12839")); assertThat ( bookRecord.getBookFormat (), je ("pevná väzba")); assertThat (bookRecord.getPublishingYear (), je ("2018"));} itemReader.close (); return null;}); }

The MetadataInstanceFactory vytvára zvyk StepExecution to je potrebné na vpichnutie nášho Step-scoped ItemReader.

Kvôli tomu, môžeme skontrolovať správanie čitateľa pomocou doInTestScope metóda.

Ďalej otestujeme JsonFileItemWriter a overiť jeho výstup:

@Test public void givenMockedStep_whenWriterCalled_thenSuccess () vyvolá výnimku {// daný FileSystemResource expectResult = nový FileSystemResource (EXPECTED_OUTPUT_ONE); FileSystemResource actualResult = nový FileSystemResource (TEST_OUTPUT); Demo kniha = nová kniha (); demoBook.setAuthor ("Grisham J."); demoBook.setName ("firma"); StepExecution stepExecution = MetaDataInstanceFactory .createStepExecution (defaultJobParameters ()); // when StepScopeTestUtils.doInStepScope (stepExecution, () -> {jsonItemWriter.open (stepExecution.getExecutionContext ()); jsonItemWriter.write (Arrays.asList (demoBook)); jsonItemWriter.close (); return null; // potom AssertFile.assertFileEquals (expectResult, actualResult); } 

Na rozdiel od predchádzajúcich testov teraz máme úplnú kontrolu nad našimi testovacími objektmi. Ako výsledok, sme zodpovední za otváranie a zatváranie I / O streamov.

5. Záver

V tomto tutoriáli sme preskúmali rôzne prístupy testovania úlohy Spring Batch.

End-to-end testovanie overuje úplné vykonanie úlohy. Testovanie jednotlivých krokov môže pomôcť v zložitých scenároch.

Nakoniec, pokiaľ ide o komponenty s rozsahovým rozsahom, môžeme použiť množstvo pomocných metód poskytovaných používateľom jarný dávkový test. Pomôžu nám pri zatĺkaní a zosmiešňovaní objektov domény Spring Batch.

Ako obvykle, môžeme preskúmať celú základňu kódov na GitHub.


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