N-LAB

JUnit 5 × MyBatis × DBUnitでRepositoryのユニットテストを実装する

投稿日: 2024年10月14日


目標

※JPAを使用している場合は適宜Repositoryの実装を読み替えてください。

※MySQLなど他のデータベースを使用している場合は適宜実装を読み替えてください。

条件


目次

  1. JUnit5とDBUnitの導入
  2. データローダーの実装
  3. 単体テストコード(UT)の実装


JUnit5とDBUnitの導入

dependencies {
    testImplementation 'org.springframework.boot:spring-boot-starter-test'
    testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
    testImplementation 'org.junit.jupiter:junit-jupiter-api:5.11.2'
    testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.11.2'
    testImplementation group: 'org.dbunit', name: 'dbunit', version: '2.+'
    testImplementation group: 'com.github.springtestdbunit', name: 'spring-test-dbunit', version: '1.3.0'
    runtimeOnly 'com.h2database:h2'
    testImplementation 'com.h2database:h2'
}
test {
    useJUnitPlatform()
}

※データベースにH2 Databaseを使用していない場合は以下の追加は不要です。
・runtimeOnly 'com.h2database:h2'
・testImplementation 'com.h2database:h2'

データローダーの実装

XmlDataLoader.java

import com.github.springtestdbunit.dataset.AbstractDataSetLoader;
import java.io.InputStream;
import org.dbunit.dataset.IDataSet;
import org.dbunit.dataset.xml.FlatXmlDataSetBuilder;
import org.springframework.core.io.Resource;

public class XmlDataLoader extends AbstractDataSetLoader {
  @Override
  protected IDataSet createDataSet(Resource resource) throws Exception {
    FlatXmlDataSetBuilder builder = new FlatXmlDataSetBuilder();
    builder.setColumnSensing(true);
    try (InputStream stream = resource.getInputStream()) {
      return builder.build(stream);
    }
  }
}

test/resources/dataset/user_find_by_id.xml

<?xml version="1.0" encoding="UTF-8"?>
<dataset>
  <user id="1" email="test1@test.com" />
  <user id="2" email="test2@test.com" password="test2" />
</dataset>


builder.setColumnSensing(true);


単体テストコード(UT)の実装

resources/schema.sql

DROP TABLE IF EXISTS user;

CREATE TABLE user (
  id INTEGER PRIMARY KEY AUTO_INCREMENT,
  email VARCHAR(255) NOT NULL,
  password VARCHAR(255)
);

User.java

@Builder
@Getter
@Setter
@ToString
public class User {
  private Long id;
  private String email;
  private String password;
}

UserRepository.java

@Repository
public class UserRepository {
  private final UserMapper userMapper;
  public UserRepository(UserMapper userMapper) {
    this.userMapper = userMapper;
  }

  public Optional<User> findById(Long id) throws Exception {
    return userMapper.findById(id);
  }
}

UserMapper.java

@Mapper
public interface UserMapper {
  Optional<User> findById(Long id);
}

resources/mapper/UserMapper.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="foo.bar.UserMapper">
  <select id="findById" resultType="foo.bar.User">
    select * from user where id = #{id}
  </select>
</mapper>

application.yml

spring:
  datasource:
    url: jdbc:h2:mem:test;NON_KEYWORDS=USER;DATABASE_TO_UPPER=false;
    username: root
    password: root
    driver-class-name: org.h2.Driver
  sql:
    init:
      mode: always
      encoding: UTF-8
  h2:
    console:
      enabled: true
      path: /h2-console
mybatis:
  configuration:
    map-underscore-to-camel-case: true
  mapper-locations: classpath*:/mapper/*.xml
  type-aliases-package: foo.bar


1. UserRepositoryTest.javaを新規作成し、以下の内容を実装します

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;

import com.github.springtestdbunit.TransactionDbUnitTestExecutionListener;
import com.github.springtestdbunit.annotation.DatabaseSetup;
import com.github.springtestdbunit.annotation.DbUnitConfiguration;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.TestExecutionListeners;
import org.springframework.test.context.junit.jupiter.SpringExtension;
import org.springframework.test.context.support.DependencyInjectionTestExecutionListener;
import org.springframework.test.context.support.DirtiesContextTestExecutionListener;
import org.springframework.transaction.annotation.Transactional;

@ExtendWith(SpringExtension.class)
@SpringBootTest
@TestExecutionListeners({
    DependencyInjectionTestExecutionListener.class,
    DirtiesContextTestExecutionListener.class,
    TransactionDbUnitTestExecutionListener.class
})
@Transactional
@DbUnitConfiguration(dataSetLoader = XmlDataLoader.class)
public class UserRepositoryTest {
  @Autowired
  private UserRepository userRepository;

  @Test
  @DisplayName("指定したIDのユーザー情報が取得できること")
  @DatabaseSetup("/dataset/user_find_by_id.xml")
  public void findById() throws Exception {
    // Arrange
    User expectedUser = User.builder()
        .id(2L)
        .email("test2@test.com")
        .password("test2")
        .build();

    // Act
    User actualUser = userRepository.findById(expectedUser.getId()).orElse(null);

    // Assert
    assertNotNull(actualUser);
    assertEquals(expectedUser.getId(), actualUser.getId());
    assertEquals(expectedUser.getEmail(), actualUser.getEmail());
    assertEquals(expectedUser.getPassword(), actualUser.getPassword());
  }
}


TransactionDbUnitTestExecutionListener.class


DependencyInjectionTestExecutionListener.class
DirtiesContextTestExecutionListener.class


以上で全ての手順は完了になります