内容
Batchのテストコード実装しました。
詳細は今度書きます。
とりあえずコードだけ。
git
ファイル構成
build.gradle
build.gradle
plugins {
id 'java'
id 'org.springframework.boot' version '3.4.0'
id 'io.spring.dependency-management' version '1.1.6'
}
group = 'com.example'
version = '0.0.1-SNAPSHOT'
java {
toolchain {
languageVersion = JavaLanguageVersion.of(23)
}
}
repositories {
mavenCentral()
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-batch'
runtimeOnly 'com.h2database:h2'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
testImplementation 'org.springframework.batch:spring-batch-test'
testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
// プロダクトコード用
compileOnly 'org.projectlombok:lombok'
annotationProcessor 'org.projectlombok:lombok'
// テストコード用
testCompileOnly 'org.projectlombok:lombok'
testAnnotationProcessor 'org.projectlombok:lombok'
}
tasks.named('test') {
useJUnitPlatform()
}
プロダクトコード
Resouces
csv
female.csv
id,name
2,hanako
3,hana
male.csv
id,name
1,taro
property
demo.properties
csv.file.path=classpath:csv/*.csv
Chunk
CsvReader
CsvReader.java
package com.example.demo.chunk;
import com.example.demo.model.User;
import org.springframework.batch.core.configuration.annotation.StepScope;
import org.springframework.batch.item.file.FlatFileItemReader;
import org.springframework.batch.item.file.MultiResourceItemReader;
import org.springframework.batch.item.file.builder.FlatFileItemReaderBuilder;
import org.springframework.batch.item.file.mapping.BeanWrapperFieldSetMapper;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.PropertySource;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.stereotype.Component;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
@Component
@PropertySource("classpath:property/demo.properties")
public class CsvReader {
@Value("${csv.file.path}")
private String filePath;
private Resource[] getCsvFiles() throws IOException {
return new PathMatchingResourcePatternResolver().getResources(filePath);
}
@StepScope
public MultiResourceItemReader<User> read() throws IOException {
System.out.println("read");
final MultiResourceItemReader<User> multiReader = new MultiResourceItemReader<>();
multiReader.setResources(getCsvFiles());
multiReader.setDelegate(singleFileReader());
return multiReader;
}
private FlatFileItemReader<User> singleFileReader() {
final String[] nameArray = new String[]{"id", "name"};
return new FlatFileItemReaderBuilder<User>()
.name("csvReader")
.linesToSkip(1)
.encoding(StandardCharsets.UTF_8.name())
.delimited()
.names(nameArray)
.fieldSetMapper(new BeanWrapperFieldSetMapper<User>() {{
setTargetType(User.class);
}})
.build();
}
}
CsvProcessor
CsvProcessor.java
package com.example.demo.chunk;
import com.example.demo.model.User;
import lombok.extern.slf4j.Slf4j;
import org.springframework.batch.core.configuration.annotation.StepScope;
import org.springframework.batch.item.ItemProcessor;
import org.springframework.stereotype.Component;
@Component
@StepScope
@Slf4j
public class CsvProcessor implements ItemProcessor<User, User> {
@Override
public User process(final User item) throws Exception {
try {
System.out.println("process");
item.setName(item.getName() + "さん");
System.out.println(item.toString());
} catch (Exception e) {
log.warn(e.getMessage(), e);
return null;
}
return item;
}
}
CsvWriter
CsvWriter.java
package com.example.demo.chunk;
import com.example.demo.model.User;
import com.example.demo.repository.UserRepository;
import org.springframework.batch.core.configuration.annotation.StepScope;
import org.springframework.batch.item.Chunk;
import org.springframework.batch.item.ItemWriter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.ArrayList;
@Component
@StepScope
public class CsvWriter implements ItemWriter<User> {
@Autowired
private UserRepository userRepository;
@Override
public void write(final Chunk<? extends User> items) throws Exception {
System.out.println("write");
userRepository.dummyBulkInsert(new ArrayList<>(items.getItems()));
System.out.println("登録完了");
}
}
Model
User
User.java
package com.example.demo.model;
import lombok.Data;
import org.springframework.batch.item.ResourceAware;
import org.springframework.core.io.Resource;
@Data
public class User implements ResourceAware {
private long id;
private String name;
private String fileName;
@Override
public void setResource(final Resource resource) {
fileName = resource.getFilename();
}
}
Repository
UserRepository
UserRepository.java
package com.example.demo.repository;
import com.example.demo.model.User;
import org.springframework.stereotype.Repository;
import java.util.List;
@Repository
public class UserRepository {
public int dummyBulkInsert(List<User> user) {
// 実際のインサート処理を記述する
return user.size();
}
}
Resource
CsvResource
CsvResource.java
package com.example.demo.resource;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.stereotype.Component;
import java.io.IOException;
@Component
public class CsvResource {
public Resource[] getResources(String filePath) throws IOException {
return new PathMatchingResourcePatternResolver().getResources(filePath);
}
}
Tasklet
CsvExistsCheckTasklet1
CsvExistsCheckTasklet1
package com.example.demo.tasklet;
import com.example.demo.resource.CsvResource;
import org.springframework.batch.core.StepContribution;
import org.springframework.batch.core.configuration.annotation.StepScope;
import org.springframework.batch.core.scope.context.ChunkContext;
import org.springframework.batch.core.step.tasklet.Tasklet;
import org.springframework.batch.repeat.RepeatStatus;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.PropertySource;
import org.springframework.core.io.Resource;
import org.springframework.stereotype.Component;
import java.io.FileNotFoundException;
import java.io.IOException;
@Component
@StepScope
@PropertySource("classpath:property/demo.properties")
public class CsvExistsCheckTasklet1 implements Tasklet {
@Value("${csv.file.path}")
private String filePath;
@Autowired
private CsvResource csvResource;
@Override
public RepeatStatus execute(StepContribution stepContribution, ChunkContext context) throws IOException {
final Resource[] resources = csvResource.getResources(filePath);
if (resources.length == 0) throw new FileNotFoundException("csvファイルが見つかりませんでした");
return RepeatStatus.FINISHED;
}
}
CsvExistsCheckTasklet2
CsvExistsCheckTasklet2
package com.example.demo.tasklet;
import org.springframework.batch.core.StepContribution;
import org.springframework.batch.core.configuration.annotation.StepScope;
import org.springframework.batch.core.scope.context.ChunkContext;
import org.springframework.batch.core.step.tasklet.Tasklet;
import org.springframework.batch.repeat.RepeatStatus;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.PropertySource;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.stereotype.Component;
import java.io.FileNotFoundException;
import java.io.IOException;
@Component
@StepScope
@PropertySource("classpath:property/demo.properties")
public class CsvExistsCheckTasklet2 implements Tasklet {
@Value("${csv.file.path}")
private String filePath;
@Override
public RepeatStatus execute(StepContribution stepContribution, ChunkContext context) throws IOException {
final Resource[] resources = new PathMatchingResourcePatternResolver().getResources(filePath);
if (resources.length == 0) throw new FileNotFoundException("csvファイルが見つかりませんでした");
return RepeatStatus.FINISHED;
}
}
BatchConfig
BatchConfig.java
package com.example.demo;
import com.example.demo.chunk.CsvProcessor;
import com.example.demo.chunk.CsvReader;
import com.example.demo.chunk.CsvWriter;
import com.example.demo.model.User;
import com.example.demo.tasklet.CsvExistsCheckTasklet1;
import com.example.demo.tasklet.CsvExistsCheckTasklet2;
import org.springframework.batch.core.Job;
import org.springframework.batch.core.Step;
import org.springframework.batch.core.job.builder.JobBuilder;
import org.springframework.batch.core.launch.support.RunIdIncrementer;
import org.springframework.batch.core.repository.JobRepository;
import org.springframework.batch.core.step.builder.StepBuilder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.transaction.PlatformTransactionManager;
import java.io.IOException;
import java.io.PrintStream;
@Configuration
public class BatchConfig {
@Autowired
private CsvExistsCheckTasklet1 tasklet;
@Autowired
private CsvReader reader;
@Autowired
private CsvProcessor processor;
@Autowired
private CsvWriter writer;
@Bean
public Step fileCheckStep(final JobRepository jobRepository, final PlatformTransactionManager transactionManager) {
return new StepBuilder("fileCheckStep", jobRepository)
.tasklet(tasklet, transactionManager)
.build();
}
@Bean
public Step demoStep(final JobRepository jobRepository, final PlatformTransactionManager transactionManager) throws IOException {
return new StepBuilder("demoStep", jobRepository)
.<User, User>chunk(10, transactionManager)
.reader(reader.read())
.processor(processor)
.writer(writer)
.build();
}
@Bean
public Job demoJob(final JobRepository jobRepository, final PlatformTransactionManager transactionManager,
final Step fileCheckStep, final Step demoStep) throws Exception {
System.setOut(new PrintStream(System.out, true, "UTF-8"));
return new JobBuilder("demoJob", jobRepository)
.incrementer(new RunIdIncrementer())
.start(fileCheckStep)
.next(demoStep)
.build();
}
}
DemoApplication
DemoApplication.java
package com.example.demo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
テストコード
Resouces
csv
プロダクトコードのほうと同じです。
パスは異なります。
property
demo.properties
csv.file.path=classpath:test/csv/*.csv
Chunk
CsvReaderTest
CsvReaderTest.java
package com.example.demo.chunk;
import com.example.demo.model.User;
import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.*;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.junit.jupiter.MockitoExtension;
import org.springframework.batch.item.file.MultiResourceItemReader;
import org.springframework.test.util.ReflectionTestUtils;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNull;
@ExtendWith(MockitoExtension.class)
@Slf4j
@DisplayName("CsvReaderTest")
public class CsvReaderTest {
@InjectMocks
private CsvReader csvReader;
@BeforeAll
public static void beginTest() {
log.info("CsvReaderTest 開始");
}
@AfterAll
public static void endTest() {
log.info("CsvReaderTest 終了");
}
@BeforeEach
public void setup() {
ReflectionTestUtils.setField(csvReader, "filePath", "classpath:test/csv/*.csv", String.class);
}
@Test
@DisplayName("readTest")
public void readTest() throws Exception {
// SETUP
log.info("readTest 開始");
final User[] expectedArray = {
createUser(2L, "hanako", "female.csv"),
createUser(3L, "hana", "female.csv"),
createUser(1L, "taro", "male.csv")
};
// WHEN
final MultiResourceItemReader<User> reader = csvReader.read();
assertEquals(expectedArray[0], reader.read());
assertEquals(expectedArray[1], reader.read());
assertEquals(expectedArray[2], reader.read());
assertNull(reader.read());
// THEN
log.info("readTest 終了");
}
private User createUser(final long id, final String name, final String fileName) {
final User user = new User();
user.setId(id);
user.setName(name);
user.setFileName(fileName);
return user;
}
}
CsvProcessorTest
CsvProcessorTest.java
package com.example.demo.chunk;
import com.example.demo.model.User;
import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.junit.jupiter.MockitoExtension;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNull;
@ExtendWith(MockitoExtension.class)
@Slf4j
@DisplayName("CsvProcessorTest")
public class CsvProcessorTest {
@InjectMocks
private CsvProcessor csvProcessor;
@BeforeAll
public static void beginTest() {
log.info("CsvProcessorTest 開始");
}
@AfterAll
public static void endTest() {
log.info("CsvProcessorTest 終了");
}
@Test
@DisplayName("executeTest_noException")
public void executeTest_noException() throws Exception {
// SETUP
log.info("executeTest_noException 開始");
final User item = createUser(1L);
final User expected = createUser(1L);
expected.setName(expected.getName() + "さん");
// WHEN
final User actual = csvProcessor.process(item);
// THEN
assertEquals(expected, actual);
log.info("executeTest_noException 終了");
}
@Test
@DisplayName("executeTest_exception")
public void executeTest_exceptionCheck() throws Exception {
// SETUP
log.info("executeTest_exception 開始");
// WHEN
final User actual = csvProcessor.process(null);
// THEN
assertNull(actual);
log.info("executeTest_exception 終了");
}
private User createUser(final long id) {
final User user = new User();
user.setId(id);
user.setName("name" + id);
user.setFileName("file" + id);
return user;
}
}
CsvWriterTest
CsvWriterTest.java
package com.example.demo.chunk;
import com.example.demo.model.User;
import com.example.demo.repository.UserRepository;
import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import org.mockito.junit.jupiter.MockitoSettings;
import org.mockito.quality.Strictness;
import org.springframework.batch.item.Chunk;
import java.io.ByteArrayOutputStream;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
@ExtendWith(MockitoExtension.class)
@MockitoSettings(strictness = Strictness.LENIENT)
@Slf4j
@DisplayName("CsvWriterTest")
public class CsvWriterTest {
@InjectMocks
private CsvWriter csvWriter;
@Mock
private UserRepository userRepository;
private final ByteArrayOutputStream outContent = new ByteArrayOutputStream();
@BeforeAll
public static void beginTest() {
log.info("CsvWriterTest 開始");
}
@AfterAll
public static void endTest() {
log.info("CsvWriterTest 終了");
}
@Test
@DisplayName("write")
public void write() throws Exception {
// SETUP
log.info("CsvWriterTest 開始");
final Chunk<User> items = new Chunk<>(new User(), new User());
// WHEN
csvWriter.write(items);
// THEN
verify(userRepository, times(1)).dummyBulkInsert(any());
log.info("CsvWriterTest 終了");
}
}
Repository
UserRepositoryTest
UserRepositoryTest.java
package com.example.demo.repository;
import com.example.demo.model.User;
import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
//import org.springframework.batch.test.context.SpringBatchTest;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
import static org.junit.jupiter.api.Assertions.assertIterableEquals;
// @SpringBatchTest // SpringBatchの機能(Job, Step)をテストするときに使うアノテーション
@SpringBootTest // RepositoryはBatch機能ではないためSpringBootTestアノテーションを使用
@Slf4j
@DisplayName("UserRepositoryTest")
class UserRepositoryTest {
@Autowired
private UserRepository userRepository;
@BeforeAll
public static void beginTest() {
log.info("UserRepositoryTest 開始");
}
@AfterAll
public static void endTest() {
log.info("UserRepositoryTest 終了");
}
@Test
@Transactional
@DisplayName("dummyBulkInsertTest")
public void dummyBulkInsertTest() {
// SETUP
log.info("dummyBulkInsertTest 開始");
final List<User> expected = List.of(createUserData(1L), createUserData(2L));
// WHEN
userRepository.dummyBulkInsert(expected);
// THEN
// List<User> actual = xxx.selectByExample();
final List<User> actual = expected; // selectでデータを取得したとする
assertIterableEquals(expected, actual);
// CLEANUP
// @Transactionalでロールバック実行
log.info("dummyBulkInsertTest 終了");
}
private User createUserData(final long id) {
final User user = new User();
user.setId(id);
user.setName("name" + id);
user.setFileName("fileName" + id);
return user;
}
}
Resource
CsvResourceTest
CsvResourceTest.java
package com.example.demo.resource;
import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.junit.jupiter.MockitoExtension;
import org.springframework.core.io.Resource;
import java.io.IOException;
import java.util.Arrays;
import static org.junit.jupiter.api.Assertions.assertArrayEquals;
@ExtendWith(MockitoExtension.class)
@Slf4j
@DisplayName("CsvReaderTest")
public class CsvResourceTest {
@InjectMocks
private CsvResource csvResource;
@BeforeAll
public static void beginTest() {
log.info("CsvResourceTest 開始");
}
@AfterAll
public static void endTest() {
log.info("CsvResourceTest 終了");
}
@Test
@DisplayName("getResourcesTest")
public void getResourcesTest() throws IOException {
// SETUP
final String filePath = "classpath:test/csv/*.csv";
final String[] expected = {"female.csv", "male.csv"};
// WHEN
final Resource[] resources = csvResource.getResources(filePath);
final String[] actual = Arrays.stream(resources).map(Resource::getFilename).toArray(String[]::new);
// THEN
assertArrayEquals(expected, actual);
log.info("getResourcesTest 開始");
}
}
Tasklet
CsvExistsCheckTasklet1Test
CsvExistsCheckTasklet1Test.java
package com.example.demo.tasklet;
import com.example.demo.resource.CsvResource;
import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import org.springframework.batch.repeat.RepeatStatus;
import org.springframework.core.io.Resource;
import org.springframework.test.util.ReflectionTestUtils;
import java.io.FileNotFoundException;
import java.io.IOException;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.when;
// @ExtendWith(クラス)でテストに使用するクラスを指定できる
// MockitoExtensionを指定するとMockitoテストが可能になる(モックが使える)
// DIしたくないときに使える
@ExtendWith(MockitoExtension.class)
@Slf4j
@DisplayName("CsvExistsCheckTaskletTest")
public class CsvExistsCheckTaskletTest1 {
@InjectMocks // モックを使いたいクラスに付与することで@MockをDIしてくれる
private CsvExistsCheckTasklet1 csvExistsCheckTasklet;
@Mock // テスト元でDIしているものをモック化する
private CsvResource csvResource;
@BeforeAll
public static void beginTest() {
log.info("CsvExistsCheckTaskletTest 開始");
}
@AfterAll
public static void endTest() {
log.info("CsvExistsCheckTaskletTest 終了");
}
@Test
@DisplayName("executeTest_existsFile")
public void executeTest_success() throws IOException {
// SETUP
log.info("executeTest_existsFile 開始");
ReflectionTestUtils.setField(csvExistsCheckTasklet, "filePath", "", String.class);
final RepeatStatus expected = RepeatStatus.FINISHED;
// WHEN
when(csvResource.getResources(anyString())).thenReturn(new Resource[]{any()});
final RepeatStatus actual = csvExistsCheckTasklet.execute(null, null);
// THEN
assertEquals(expected, actual);
log.info("executeTest_existsFile 終了");
}
@Test
@DisplayName("executeTest_notExistsFile")
public void executeTest_fail() throws IOException {
// SETUP
log.info("executeTest_notExistsFile 開始");
ReflectionTestUtils.setField(csvExistsCheckTasklet, "filePath", "", String.class);
// THEN
when(csvResource.getResources(anyString())).thenReturn(new Resource[]{});
assertThrows(FileNotFoundException.class, () -> csvExistsCheckTasklet.execute(null, null));
log.info("executeTest_notExistsFile 終了");
}
}
CsvExistsCheckTasklet2Test
CsvExistsCheckTasklet2.java
package com.example.demo.tasklet;
import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.junit.jupiter.MockitoExtension;
import org.springframework.batch.repeat.RepeatStatus;
import org.springframework.test.util.ReflectionTestUtils;
import java.io.FileNotFoundException;
import java.io.IOException;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
// @ExtendWith(クラス)でテストに使用するクラスを指定できる
// MockitoExtensionを指定するとMockitoテストが可能になる(モックが使える)
// DIしたくないときに使える
@ExtendWith(MockitoExtension.class)
@Slf4j
@DisplayName("CsvExistsCheckTaskletTest")
public class CsvExistsCheckTaskletTest2 {
@InjectMocks // モックを使いたいクラスに付与することで@MockをDIしてくれる
private CsvExistsCheckTasklet2 csvExistsCheckTasklet;
// @Mock // テスト元でDIしているものをモック化する
// private XXX xxx;
@BeforeAll
public static void beginTest() {
log.info("CsvExistsCheckTaskletTest 開始");
}
@AfterAll
public static void endTest() {
log.info("CsvExistsCheckTaskletTest 終了");
}
@Test
@DisplayName("executeTest_existsFile")
public void executeTest_success() throws IOException {
// SETUP
log.info("executeTest_existsFile 開始");
ReflectionTestUtils.setField(csvExistsCheckTasklet, "filePath", "classpath:test/csv/*.csv", String.class);
final RepeatStatus expected = RepeatStatus.FINISHED;
// WHEN
final RepeatStatus actual = csvExistsCheckTasklet.execute(null, null);
// THEN
assertEquals(expected, actual);
log.info("executeTest_existsFile 終了");
}
@Test
@DisplayName("executeTest_notExistsFile")
public void executeTest_fail() throws IOException {
// SETUP
log.info("executeTest_notExistsFile 開始");
ReflectionTestUtils.setField(csvExistsCheckTasklet, "filePath", "classpath:test/csv/empty/*.csv", String.class);
// THEN
assertThrows(FileNotFoundException.class, () -> csvExistsCheckTasklet.execute(null, null));
log.info("executeTest_notExistsFile 終了");
}
}
BatchConfigTest
BatchConfigTest.java
package com.example.demo;
import com.example.demo.chunk.CsvProcessor;
import com.example.demo.chunk.CsvReader;
import com.example.demo.chunk.CsvWriter;
import com.example.demo.repository.UserRepository;
import com.example.demo.resource.CsvResource;
import com.example.demo.tasklet.CsvExistsCheckTasklet1;
import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.springframework.batch.core.ExitStatus;
import org.springframework.batch.core.JobExecution;
import org.springframework.batch.test.JobLauncherTestUtils;
import org.springframework.batch.test.context.SpringBatchTest;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.test.context.ContextConfiguration;
import static org.junit.jupiter.api.Assertions.assertEquals;
@SpringBatchTest
// DI対象のクラスを列挙する
@ContextConfiguration(classes = {BatchConfig.class, CsvExistsCheckTasklet1.class, CsvReader.class, CsvProcessor.class, CsvWriter.class, CsvResource.class, UserRepository.class})
@EnableAutoConfiguration // 必要そうなbeanを自動で構成してくれる
@Slf4j
@DisplayName("BatchConfigTest")
public class BatchConfigTest {
@Autowired
private JobLauncherTestUtils jobLauncherTestUtils;
@BeforeAll
public static void beginTest() {
log.info("BatchConfigTest 開始");
}
@AfterAll
public static void endTest() {
log.info("BatchConfigTest 終了");
}
@Test
@DisplayName("fileCheckStepTest")
public void fileCheckStepTest() {
// SETUP
log.info("executeTest_existsFile 開始");
// WHEN
// 読み込まれたクラスのプロパティファイル読み込みはtest側が使用される
final JobExecution jobExecution = jobLauncherTestUtils.launchStep("fileCheckStep");
// THEN
assertEquals(ExitStatus.COMPLETED, jobExecution.getExitStatus());
log.info("executeTest_existsFile 終了");
}
@Test
@DisplayName("demoStepTest")
public void demoStepTest() {
// SETUP
log.info("demoStepTest 開始");
// WHEN
final JobExecution jobExecution = jobLauncherTestUtils.launchStep("demoStep");
// THEN
assertEquals(ExitStatus.COMPLETED, jobExecution.getExitStatus());
log.info("demoStepTest 終了");
}
@Test
@DisplayName("demoJobTest")
public void demoJobTest() throws Exception {
// SETUP
log.info("demoJobTest 開始");
// WHEN
final JobExecution jobExecution = jobLauncherTestUtils.launchJob();
// THEN
assertEquals(ExitStatus.COMPLETED, jobExecution.getExitStatus());
log.info("demoJobTest 終了");
}
}
DemoApplicationTests
DemoApplication.java
package com.example.demo;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest
class DemoApplicationTests {
@Test
void contextLoads() {
}
}
参考
@Valueのような外部値をテストで扱う方法について記載
Junitについて記載
アサーションについて
Mockitoについて
テスト 実行回数の検証について
テスト 戻り値設定について
Spring Boot テストアノテーションについて