0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Spring Batch5 Junit5(テストコード)実装

Posted at

内容

Batchのテストコード実装しました。
詳細は今度書きます。
とりあえずコードだけ。

git

ファイル構成

image.png

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 テストアノテーションについて

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?