⇧ amazing...
Spring Batchの単体テストに必要な依存関係
公式のドキュメントでは見つけられなかったのですが、
We included the spring-boot-starter-test and spring-batch-test which bring in some necessary helper methods, listeners and runners for testing Spring Batch applications.
⇧ 上記サイト様によりますと、
- spring-boot-starter-test
- spring-batch-test
の2つの依存関係があれば良いらしい。
JUnitとかかは、spring-boot-starter-testの依存関係に含まれてるらしい。
Spring Batchの単体テストを実施してみる
というわけで、
⇧ 上記サイト様の情報を参考に、Spring Batchの単体テストを実施してみる。
利用するプロジェクトは、
⇧ 上記の記事のものになります。
まずは、依存関係を追加で。spring-boot-starter-testはデフォルトで追加されてたので、spring-batch-testを追加で。
■/mybatis-example/build.gradle
plugins { id 'org.springframework.boot' version '2.7.5' id 'io.spring.dependency-management' version '1.0.15.RELEASE' id 'java' } group = 'com.example' version = '0.0.1-SNAPSHOT' sourceCompatibility = '11' configurations { compileOnly { extendsFrom annotationProcessor } } repositories { mavenCentral() } dependencies { implementation 'org.springframework.boot:spring-boot-starter-thymeleaf' implementation 'org.springframework.boot:spring-boot-starter-web' // https://mvnrepository.com/artifact/org.mybatis.spring.boot/mybatis-spring-boot-starter implementation group: 'org.mybatis.spring.boot', name: 'mybatis-spring-boot-starter', version: '2.2.2' // https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-batch implementation group: 'org.springframework.boot', name: 'spring-boot-starter-batch', version: '2.7.5' implementation 'com.opencsv:opencsv:5.7.1' compileOnly 'org.projectlombok:lombok' developmentOnly 'org.springframework.boot:spring-boot-devtools' runtimeOnly 'org.postgresql:postgresql' annotationProcessor 'org.projectlombok:lombok' testImplementation 'org.springframework.boot:spring-boot-starter-test' implementation 'org.springframework.batch:spring-batch-test:4.3.7' } tasks.named('test') { useJUnitPlatform() }
で、テストクラスを作成して実行するもエラー。
⇧ 上記サイト様によりますと、テストに合わせて本番のソースコードを修正する必要があるという本末転倒ぶりがSpring Frameworkということらしい、残念過ぎる...
テストに合わせて本番で正常に動いているコードを直すのは御法度だと思うのですが、残念ながらSpring Frameworkは、テストに合わせろってことらしいので合わせますか。
今回、変更、追加してるファイルは以下。
変更、追加の在ったファイルの内容を記載。
■/mybatis-example/src/main/java/com/example/demo/batch/user/UserBatchConfig.java
package com.example.demo.batch.user; import java.io.IOException; import java.nio.charset.StandardCharsets; import org.springframework.batch.core.Job; import org.springframework.batch.core.Step; import org.springframework.batch.core.configuration.annotation.EnableBatchProcessing; import org.springframework.batch.core.configuration.annotation.JobBuilderFactory; import org.springframework.batch.core.configuration.annotation.StepBuilderFactory; import org.springframework.batch.core.configuration.annotation.StepScope; import org.springframework.batch.core.job.flow.FlowExecutionStatus; import org.springframework.batch.core.job.flow.JobExecutionDecider; import org.springframework.batch.core.launch.support.RunIdIncrementer; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; import org.springframework.core.io.FileSystemResource; import com.example.demo.dto.CsvUser; import com.example.demo.entity.ShikokuOhenroUser; @Configuration @EnableBatchProcessing @ComponentScan("com.example.demo") public class UserBatchConfig { @Autowired private JobBuilderFactory jobBuilderFactory; @Autowired private StepBuilderFactory stepBuilderFactory; // @Bean // @StepScope // public Resource userCsvResource(@Value("#{jobParameters['filePath']}") String filePath) { // return new FileSystemResource(filePath); // } @Bean @StepScope public UserReader<CsvUser> csvUserReader(CsvUserMapper csvUserMapper, @Value("#{jobParameters['filePath']}") String filePath) throws IOException { UserReader<CsvUser> reader = new UserReader<>(); reader.setCharset(StandardCharsets.UTF_8); reader.setStrict(true); //reader.setResource(new ClassPathResource(filePath)); reader.setResource(new FileSystemResource(filePath)); reader.setLinesToSkip(1); reader.setHeaders(new String[] {"last_name", "first_name", "rome_last_name", "rome_first_name", "ohenro_ids"}); reader.setFieldSetMapper(csvUserMapper); reader.setDelimiter(','); reader.setQuotedChar('"'); reader.setName("csvReader"); return reader; } @Bean public Step step1(UserReader<CsvUser> userReader, UserWriter userWriter, UserProcessor userProcessor) { return stepBuilderFactory.get("csvItemReaderStep") .<CsvUser, ShikokuOhenroUser> chunk(10) .reader(userReader) .processor(userProcessor) .writer(userWriter) .build(); } // @Bean // public Job importUserJob(Step step1) { // return jobBuilderFactory.get("importUserJob") // .incrementer(new RunIdIncrementer()) // .start(step1) // .build(); // } @Bean public Job userJob(Step step1) { return jobBuilderFactory.get("userJob") .incrementer(new RunIdIncrementer()) .start(step1) .next(decider()) .on("Success") .end() .build() .build(); } @Bean public JobExecutionDecider decider() { System.out.println("Made it to the decider"); return (jobExecution, stepExecution) -> new FlowExecutionStatus("Success"); } }
■/mybatis-example/src/test/java/com/example/demo/batch/user/UserBatchTest.java
package com.example.demo.batch.user; import static org.hamcrest.CoreMatchers.*; import static org.hamcrest.MatcherAssert.*; import java.nio.file.Paths; import org.junit.After; import org.junit.Before; import org.junit.jupiter.api.Test; import org.junit.runner.RunWith; import org.springframework.batch.core.ExitStatus; import org.springframework.batch.core.Job; import org.springframework.batch.core.JobExecution; import org.springframework.batch.core.JobParameters; import org.springframework.batch.core.JobParametersBuilder; import org.springframework.batch.test.JobLauncherTestUtils; import org.springframework.batch.test.JobRepositoryTestUtils; import org.springframework.batch.test.context.SpringBatchTest; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.junit4.SpringRunner; @RunWith(SpringRunner.class) @SpringBatchTest @SpringBootTest(classes= {UserBatchConfig.class}) //@EnableAutoConfiguration //@ContextConfiguration(classes = { UserBatchConfig.class }) //@TestExecutionListeners({ DependencyInjectionTestExecutionListener.class, DirtiesContextTestExecutionListener.class }) //@DirtiesContext(classMode = ClassMode.AFTER_CLASS) public class UserBatchTest { private static final String TEST_INPUT = Paths.get("src/test/resources/test/test-input.csv").toAbsolutePath().toString(); @Autowired private Job userJob; @Autowired private JobLauncherTestUtils jobLauncherTestUtils; @Autowired private JobRepositoryTestUtils jobRepositoryTestUtils; @Before public void before() { jobLauncherTestUtils.setJob(userJob); } @After public void cleanUp() { jobRepositoryTestUtils.removeJobExecutions(); } private JobParameters defaultJobParameters() { JobParametersBuilder paramsBuilder = new JobParametersBuilder(); paramsBuilder.addLong("time", System.currentTimeMillis()); paramsBuilder.addString("filePath", TEST_INPUT); return paramsBuilder.toJobParameters(); } @Test public void testJob() throws Exception { JobExecution jobExecution = jobLauncherTestUtils.launchJob(defaultJobParameters()); //JobInstance actualJobInstance = jobExecution.getJobInstance(); ExitStatus actualJobExitStatus = jobExecution.getExitStatus(); //assertThat(actualJobInstance.getJobName(), is("transformBooksRecords")); assertThat(actualJobExitStatus.getExitCode(), is("COMPLETED")); } }
■/mybatis-example/src/test/resources/test/test-input.csv
last_name,first_name,rome_last_name,rome_first_name,ohenro_ids "鈴木","二郎","suzuki","jiro","1,2,3,4,5,6" "鈴木","三郎","suzuki","saburo","24,25,26,27,28" "鈴木","四郎","suzuki","shiro","40,41,42,43,44,45,46" "鈴木","五郎","suzuki","goro","81,82,83,84,85,86" "鈴木","六郎","suzuki","rokuro","1,2,3,4,5,6" "鈴木","七郎","suzuki","shichiro","24,25,26,27,28,29" "鈴木","八郎","suzuki","hachiro","40,41,42,43,44,45,46,47" "鈴木","九郎","suzuki","kyuro","81,82,83,84,85,86" "鈴木","十郎","suzuki","jyuro","1,2,3,4,5,6"
で、「パッケージ・エクスプローラー」でテストクラスを選択した状態で右クリックし、「実行(R)」>「JUnit テスト」を選択。
■テスト実行前
■テスト実行後
テストデータのCSVファイルのデータがINSERTされました。
それにしても、公式のドキュメントの通り実施しても動かないとか、最早ドキュメントの意味無いですね...
毎度モヤモヤ感が半端ない...
今回はこのへんで。