JUnit

各DB上でtruncate文を実行した際の挙動をJUnit5 DBUnitで試してみた

truncate table文によって、テーブルの全データを削除することができるが、truncate table文を実行した後でロールバックできるかどうかは、DBの種類によって異なる。

今回は、JUnit5 DBUnitを利用して、truncate table文を実行した時の動きを確認してみたので、そのサンプルプログラムを共有する。

前提条件

下記記事の実装が完了していること。

各DBのIN句で1000件を超える項目を指定してみたOracleデータベースの場合、IN句で1000件を超える項目を指定するとエラーになってしまうが、他のDBではIN句に1001件の項目を...
JUnit5でDBUnitの@DatabaseSetupや@ExpectedDatabaseというアノテーションを利用してみたデータベースのデータ検索・追加・更新・削除のテストを実施するDBUnitというツールで利用する@DatabaseSetupや@Expec...

やってみたこと

  1. 作成したサンプルプログラムの構成
  2. Oracleの場合のソースコードとテスト実行結果
  3. MySQLの場合のソースコードとテスト実行結果
  4. PostgreSQLの場合のソースコードとテスト実行結果
  5. SQL Serverの場合のソースコードとテスト実行結果

作成したサンプルプログラムの構成

作成したサンプルプログラムの構成は以下の通り。
サンプルプログラムの構成
なお、上記の赤枠は、このブログで掲載するソースコードを示す。

test.propertiesの内容は以下の通りで、JUnit5 DBUnitで利用する各DBの接続先を示していて、各DBの接続定義となるDemoTest~Configクラスで参照している。

# DB接続先(Oracle)
spring.datasourceut-ora.url=jdbc:oracle:thin:@localhost:1521:xe
spring.datasourceut-ora.username=USER01
spring.datasourceut-ora.password=USER01
spring.datasourceut-ora.driverClassName=oracle.jdbc.driver.OracleDriver
# DB接続先(MySQL)
spring.datasourceut-ms.url=jdbc:mysql://localhost:3306/user01?serverTimezone=JST
spring.datasourceut-ms.username=USER01
spring.datasourceut-ms.password=USER01
spring.datasourceut-ms.driverClassName=com.mysql.cj.jdbc.Driver
# DB接続情報(PostgreSQL)
spring.datasourceut-ps.url=jdbc:postgresql://localhost:5432/USER01
spring.datasourceut-ps.username=USER01
spring.datasourceut-ps.password=USER01
spring.datasourceut-ps.driverClassName=org.postgresql.Driver
# DB接続先(SQLServer)
spring.datasourceut-ss.url=jdbc:sqlserver://localhost:1433;databaseName=master
spring.datasourceut-ss.username=USER01
spring.datasourceut-ss.password=USER01
spring.datasourceut-ss.driverClassName=com.microsoft.sqlserver.jdbc.SQLServerDriver

また、上記赤枠以外のソースコード内容は、以下のサイトを参照のこと。
https://github.com/purin-it/java/tree/master/junit5-dbunit-truncate-table/demo



サラリーマン型フリーランスSEという働き方でお金の不安を解消しよう先日、「サラリーマン型フリーランスSE」という働き方を紹介するYouTube動画を視聴しましたので、その内容をご紹介します。 「サ...

Oracleの場合のソースコードとテスト実行結果

テスト対象となるMapperの内容は、以下の通り。

package com.example.demo.mapper.ora;

import com.example.demo.mapper.UserData;
import org.apache.ibatis.annotations.Mapper;
import java.util.List;

@Mapper
public interface UserDataMapperOra {

    /**
     * Oracleでユーザーデータテーブル(user_data)の全データを取得する
     * @return ユーザーデータテーブル(user_data)の全データ
     */
    List<UserData> findAll();

    /**
     * Oracleでユーザーデータテーブル(user_data)の全データを削除する
     */
    void truncateUserData();
}
<?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="com.example.demo.mapper.ora.UserDataMapperOra">
    <resultMap id="userDataResultMap" type="com.example.demo.mapper.UserData" >
        <id column="id" property="id" jdbcType="BIGINT" />
        <result column="name" property="name" jdbcType="VARCHAR" />
        <result column="birthY" property="birthY" jdbcType="VARCHAR" />
        <result column="birthM" property="birthM" jdbcType="VARCHAR" />
        <result column="birthD" property="birthD" jdbcType="VARCHAR" />
        <result column="sex" property="sex" jdbcType="VARCHAR" />
        <result column="memo" property="memo" jdbcType="VARCHAR" />
        <result column="sex_value" property="sex_value" jdbcType="VARCHAR" />
    </resultMap>
    <select id="findAll" resultMap="userDataResultMap">
        SELECT
              id
            , name
            , birth_year as birthY
            , birth_month as birthM
            , birth_day as birthD
            , sex
            , memo
            , CASE sex
              WHEN '1' THEN '男'
              WHEN '2' THEN '女'
              ELSE ''
              END AS sex_value
        FROM USER_DATA
    </select>
    <update id="truncateUserData">
        TRUNCATE TABLE USER_DATA
    </update>
</mapper>

また、JUnit5 DBUnitで利用するDB接続先設定の内容は、以下の通り。

package com.example.demo.mapper.ora;

import com.github.springtestdbunit.bean.DatabaseConfigBean;
import com.github.springtestdbunit.bean.DatabaseDataSourceConnectionFactoryBean;
import org.dbunit.ext.oracle.Oracle10DataTypeFactory;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Primary;
import org.springframework.context.annotation.PropertySource;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.PlatformTransactionManager;

import javax.sql.DataSource;

// MyBatisのテストを実行する際のDB接続定義
// @MybatisTestアノテーションでテストを実行する際、
// Spring Bootアプリケーションが起動するようにする。
// その際、com.example.demo.mapper.oraフォルダ下のインスタンス
// (UserDataMapper)のみがDIで使用できるようになる。
@SpringBootApplication
@PropertySource(value = {"classpath:test.properties"})
public class DemoTestOraConfig {

    /**
     * Oracleのデータソースプロパティ(UT)を生成する.
     * @return Oracleのデータソースプロパティ(UT)
     */
    @Bean(name = {"datasourceOraProperties"})
    @Primary
    @ConfigurationProperties(prefix = "spring.datasourceut-ora")
    public DataSourceProperties datasourceOraProperties() {
        return new DataSourceProperties();
    }

    /**
     * Oracleのデータソース(UT)を生成する.
     * @param properties Oracleのデータソースプロパティ(UT)
     * @return Oracleのデータソース(UT)
     */
    @Bean(name = {"dataSourceOra"})
    @Primary
    public DataSource datasourceOra(
            @Qualifier("datasourceOraProperties") DataSourceProperties properties) {
        return properties.initializeDataSourceBuilder().build();
    }

    /**
     * Oracleのトランザクションマネージャ(UT)を生成する.
     * @param dataSourceOra Oracleのデータソース(UT)
     * @return Oracleのトランザクションマネージャ(UT)
     */
    @Bean(name = {"txManagerOra"})
    @Primary
    public PlatformTransactionManager txManagerOra(
             @Qualifier("dataSourceOra") DataSource dataSourceOra) {
        return new DataSourceTransactionManager(dataSourceOra);
    }

    /**
     * OracleのDB接続設定(UT)を生成する.
     * @return OracleのDB接続設定(UT)
     */
    @Bean(name = {"dbUnitDatabaseConfigOra"})
    public DatabaseConfigBean dbUnitDatabaseConfigOra() {
        DatabaseConfigBean bean = new DatabaseConfigBean();
        bean.setAllowEmptyFields(true);
        bean.setDatatypeFactory(new Oracle10DataTypeFactory());
        return bean;
    }

    /**
     * Oracleのデータソースコネクションファクトリ(UT)を生成する.
     * @param dbUnitDatabaseConfigOra OracleのDB接続設定(UT)
     * @param dataSourceOra           Oracleのデータソース(UT)
     * @return Oracleのデータソースコネクションファクトリ(UT)
     */
    @Bean(name = {"dbUnitDatabaseConnectionOra"})
    public DatabaseDataSourceConnectionFactoryBean dbUnitDatabaseConnectionOra(
          @Qualifier("dbUnitDatabaseConfigOra") DatabaseConfigBean dbUnitDatabaseConfigOra,
          @Qualifier("dataSourceOra") DataSource dataSourceOra) {
        DatabaseDataSourceConnectionFactoryBean bean 
            = new DatabaseDataSourceConnectionFactoryBean(dataSourceOra);
        bean.setDatabaseConfig(dbUnitDatabaseConfigOra);
        bean.setSchema("USER01");
        return bean;
    }
}

さらに、Mapperのテストクラスの内容は以下の通りで、truncate table文とその実行前後のデータを取得している。

package com.example.demo.mapper.ora;

import com.example.demo.mapper.DemoXlsDataSetLoader;
import com.example.demo.mapper.UserData;
import com.github.springtestdbunit.DbUnitTestExecutionListener;
import com.github.springtestdbunit.TransactionDbUnitTestExecutionListener;
import com.github.springtestdbunit.annotation.DbUnitConfiguration;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mybatis.spring.boot.test.autoconfigure.MybatisTest;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase;
import org.springframework.test.context.TestExecutionListeners;
import org.springframework.test.context.support.DependencyInjectionTestExecutionListener;
import org.springframework.test.context.support.DirtiesContextTestExecutionListener;

import java.util.List;

import static org.junit.Assert.assertEquals;

// JUnit5ベースでMyBatisのテストを実行する
@MybatisTest
@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE)
@TestExecutionListeners({DependencyInjectionTestExecutionListener.class
        , DirtiesContextTestExecutionListener.class
        , TransactionDbUnitTestExecutionListener.class
        , DbUnitTestExecutionListener.class})
@DbUnitConfiguration(dataSetLoader = DemoXlsDataSetLoader.class
        , databaseConnection = {"dbUnitDatabaseConnectionOra"})
public class UserDataTruncateTestOra {

    /**
     * ユーザーデータテーブル(user_data)へアクセスするマッパー
     */
    @Autowired
    private UserDataMapperOra userDataMapperOra;

    /**
     * 各テストメソッドを実行する前に行う処理を定義する.
     */
    @BeforeEach
    public void beforeTest() {
        System.out.println();
        System.out.println("*** UserDataTruncateTestOraクラス テスト結果 start ***");
    }

    /**
     * truncate文の実行結果を検証する.
     */
    @Test
    public void userDataTest() {
        // ユーザーデータ削除する前のデータを確認
        System.out.println("*** ユーザーデータテーブル(user_data)のデータ Truncate前 ***");
        List<UserData> userDataList = userDataMapperOra.findAll();
        for (UserData userData : userDataList) {
            System.out.println(userData);
        }

        // ユーザーデータを削除
        userDataMapperOra.truncateUserData();

        // ユーザーデータ削除した後のデータを確認
        System.out.println("*** ユーザーデータテーブル(user_data)のデータ Truncate後 ***");
        userDataList = userDataMapperOra.findAll();
        System.out.println(userDataList);
        assertEquals(0, userDataList.size());
    }

    /**
     * 各テストメソッドを実行した後に行う処理を定義する.
     */
    @AfterEach
    public void afterTestClass() {
        System.out.println("*** UserDataTruncateTestOraクラス テスト結果 end ***");
        System.out.println();
    }
}

上記テストクラスの実行結果は以下の通りで、truncate table文の実行でコミットされていることが確認できる。

<テストクラス実行前>
Oracle_実行前

<テストクラスの実行>
Oracle_実行

<テストクラス実行後>
Oracle_実行後



ウズウズカレッジJavaコースはわかりやすい動画教材と充実した就業サポートで優良企業を目指せるプログラミングスクールだったJavaは、世界中で広く使われていて、現在の需要が高く将来性もある開発言語になります。 https://www.acrovision....

MySQLの場合のソースコードとテスト実行結果

テスト対象となるMapperの内容は、以下の通り。

package com.example.demo.mapper.ms;

import com.example.demo.mapper.UserData;
import org.apache.ibatis.annotations.Mapper;
import java.util.List;

@Mapper
public interface UserDataMapperMs {

    /**
     * MySQLでユーザーデータテーブル(user_data)の全データを取得する
     * @return ユーザーデータテーブル(user_data)の全データ
     */
    List<UserData> findAll();

    /**
     * MySQLでユーザーデータテーブル(user_data)の全データを削除する
     */
    void truncateUserData();
}
<?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="com.example.demo.mapper.ms.UserDataMapperMs">
    <resultMap id="userDataResultMap" type="com.example.demo.mapper.UserData" >
        <id column="id" property="id" jdbcType="BIGINT" />
        <result column="name" property="name" jdbcType="VARCHAR" />
        <result column="birthY" property="birthY" jdbcType="VARCHAR" />
        <result column="birthM" property="birthM" jdbcType="VARCHAR" />
        <result column="birthD" property="birthD" jdbcType="VARCHAR" />
        <result column="sex" property="sex" jdbcType="VARCHAR" />
        <result column="memo" property="memo" jdbcType="VARCHAR" />
        <result column="sex_value" property="sex_value" jdbcType="VARCHAR" />
    </resultMap>
    <select id="findAll" resultMap="userDataResultMap">
        SELECT
              id
            , name
            , birth_year as birthY
            , birth_month as birthM
            , birth_day as birthD
            , sex
            , memo
            , CASE sex
              WHEN '1' THEN '男'
              WHEN '2' THEN '女'
              ELSE ''
              END AS sex_value
        FROM USER_DATA
    </select>
    <update id="truncateUserData">
        TRUNCATE TABLE USER_DATA
    </update>
</mapper>

また、JUnit5 DBUnitで利用するDB接続先設定の内容は、以下の通り。

package com.example.demo.mapper.ms;

import com.github.springtestdbunit.bean.DatabaseConfigBean;
import com.github.springtestdbunit.bean.DatabaseDataSourceConnectionFactoryBean;
import org.dbunit.ext.mysql.MySqlDataTypeFactory;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Primary;
import org.springframework.context.annotation.PropertySource;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.PlatformTransactionManager;

import javax.sql.DataSource;

// MyBatisのテストを実行する際のDB接続定義
// @MybatisTestアノテーションでテストを実行する際、
// Spring Bootアプリケーションが起動するようにする。
// その際、com.example.demo.mapper.msフォルダ下のインスタンス
// (UserDataMapper)のみがDIで使用できるようになる。
@SpringBootApplication
@PropertySource(value = {"classpath:test.properties"})
public class DemoTestMsConfig {

    /**
     * MySQLのデータソースプロパティ(UT)を生成する.
     * @return MySQLのデータソースプロパティ(UT)
     */
    @Bean(name = {"datasourceMsProperties"})
    @Primary
    @ConfigurationProperties(prefix = "spring.datasourceut-ms")
    public DataSourceProperties datasourceMsProperties() {
        return new DataSourceProperties();
    }

    /**
     * MySQLのデータソース(UT)を生成する.
     * @param properties MySQLのデータソースプロパティ(UT)
     * @return MySQLのデータソース(UT)
     */
    @Bean(name = {"dataSourceMs"})
    @Primary
    public DataSource datasourceMs(
            @Qualifier("datasourceMsProperties") DataSourceProperties properties) {
        return properties.initializeDataSourceBuilder().build();
    }

    /**
     * MySQLのトランザクションマネージャ(UT)を生成する.
     * @param dataSourceMs MySQLのデータソース(UT)
     * @return MySQLのトランザクションマネージャ(UT)
     */
    @Bean(name = {"txManagerMs"})
    @Primary
    public PlatformTransactionManager txManagerMs(
            @Qualifier("dataSourceMs") DataSource dataSourceMs) {
        return new DataSourceTransactionManager(dataSourceMs);
    }

    /**
     * MySQLのDB接続設定(UT)を生成する.
     * @return MySQLのDB接続設定(UT)
     */
    @Bean(name = {"dbUnitDatabaseConfigMs"})
    public DatabaseConfigBean dbUnitDatabaseConfigMs() {
        DatabaseConfigBean bean = new DatabaseConfigBean();
        bean.setAllowEmptyFields(true);
        bean.setDatatypeFactory(new MySqlDataTypeFactory());
        return bean;
    }

    /**
     * MySQLのデータソースコネクションファクトリ(UT)を生成する.
     * @param dbUnitDatabaseConfigMs MySQLのDB接続設定(UT)
     * @param dataSourceMs           MySQLのデータソース(UT)
     * @return MySQLのデータソースコネクションファクトリ(UT)
     */
    @Bean(name = {"dbUnitDatabaseConnectionMs"})
    public DatabaseDataSourceConnectionFactoryBean dbUnitDatabaseConnectionOra(
          @Qualifier("dbUnitDatabaseConfigMs") DatabaseConfigBean dbUnitDatabaseConfigMs,
          @Qualifier("dataSourceMs") DataSource dataSourceMs) {
        DatabaseDataSourceConnectionFactoryBean bean 
            = new DatabaseDataSourceConnectionFactoryBean(dataSourceMs);
        bean.setDatabaseConfig(dbUnitDatabaseConfigMs);
        return bean;
    }
}

さらに、Mapperのテストクラスの内容は以下の通りで、truncate table文とその実行前後のデータを取得している。

package com.example.demo.mapper.ms;

import com.example.demo.mapper.DemoXlsDataSetLoader;
import com.example.demo.mapper.UserData;
import com.github.springtestdbunit.DbUnitTestExecutionListener;
import com.github.springtestdbunit.TransactionDbUnitTestExecutionListener;
import com.github.springtestdbunit.annotation.DbUnitConfiguration;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mybatis.spring.boot.test.autoconfigure.MybatisTest;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase;
import org.springframework.test.context.TestExecutionListeners;
import org.springframework.test.context.support.DependencyInjectionTestExecutionListener;
import org.springframework.test.context.support.DirtiesContextTestExecutionListener;

import java.util.List;

import static org.junit.Assert.assertEquals;

// JUnit5ベースでMyBatisのテストを実行する
@MybatisTest
@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE)
@TestExecutionListeners({DependencyInjectionTestExecutionListener.class
        , DirtiesContextTestExecutionListener.class
        , TransactionDbUnitTestExecutionListener.class
        , DbUnitTestExecutionListener.class})
@DbUnitConfiguration(dataSetLoader = DemoXlsDataSetLoader.class
        , databaseConnection = {"dbUnitDatabaseConnectionMs"})
public class UserDataTruncateTestMs {

    /**
     * ユーザーデータテーブル(user_data)へアクセスするマッパー
     */
    @Autowired
    private UserDataMapperMs userDataMapperMs;

    /**
     * 各テストメソッドを実行する前に行う処理を定義する.
     */
    @BeforeEach
    public void beforeTest() {
        System.out.println();
        System.out.println("*** UserDataTruncateTestMsクラス テスト結果 start ***");
    }

    /**
     * truncate文の実行結果を検証する.
     */
    @Test
    public void userDataTest() {
        // ユーザーデータ削除する前のデータを確認
        System.out.println("*** ユーザーデータテーブル(user_data)のデータ Truncate前 ***");
        List<UserData> userDataList = userDataMapperMs.findAll();
        for (UserData userData : userDataList) {
            System.out.println(userData);
        }
        System.out.println();

        // ユーザーデータを削除
        userDataMapperMs.truncateUserData();

        // ユーザーデータ削除した後のデータを確認
        System.out.println("*** ユーザーデータテーブル(user_data)のデータ Truncate後 ***");
        userDataList = userDataMapperMs.findAll();
        System.out.println(userDataList);
        assertEquals(0, userDataList.size());
    }

    /**
     * 各テストメソッドを実行した後に行う処理を定義する.
     */
    @AfterEach
    public void afterTestClass() {
        System.out.println("*** UserDataTruncateTestMsクラス テスト結果 end ***");
        System.out.println();
    }
}

上記テストクラスの実行結果は以下の通りで、truncate table文の実行でコミットされていることが確認できる。

<テストクラス実行前>
MySQL_実行前

<テストクラスの実行>
MySQL_実行

<テストクラス実行後>
MySQL_実行後



「EaseUS Todo Backup」は様々な形でバックアップ取得が行える便利ツールだったパソコン内のデータを、ファイル/パーティション/ディスク等の様々な単位でバックアップしたり、バックアップのスケジュール設定や暗号化設定も...

PostgreSQLの場合のソースコードとテスト実行結果

テスト対象となるMapperの内容は、以下の通り。

package com.example.demo.mapper.ps;

import com.example.demo.mapper.UserData;
import org.apache.ibatis.annotations.Mapper;
import java.util.List;

@Mapper
public interface UserDataMapperPs {

    /**
     * PostgreSQLでユーザーデータテーブル(user_data)の全データを取得する
     * @return ユーザーデータテーブル(user_data)の全データ
     */
    List<UserData> findAll();

    /**
     * PostgreSQLでユーザーデータテーブル(user_data)の全データを削除する
     */
    void truncateUserData();
}
<?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="com.example.demo.mapper.ps.UserDataMapperPs">
    <resultMap id="userDataResultMap" type="com.example.demo.mapper.UserData" >
        <id column="id" property="id" jdbcType="BIGINT" />
        <result column="name" property="name" jdbcType="VARCHAR" />
        <result column="birthY" property="birthY" jdbcType="VARCHAR" />
        <result column="birthM" property="birthM" jdbcType="VARCHAR" />
        <result column="birthD" property="birthD" jdbcType="VARCHAR" />
        <result column="sex" property="sex" jdbcType="VARCHAR" />
        <result column="memo" property="memo" jdbcType="VARCHAR" />
        <result column="sex_value" property="sex_value" jdbcType="VARCHAR" />
    </resultMap>
    <select id="findAll" resultMap="userDataResultMap">
        SELECT
              id
            , name
            , birth_year as birthY
            , birth_month as birthM
            , birth_day as birthD
            , sex
            , memo
            , CASE sex
              WHEN '1' THEN '男'
              WHEN '2' THEN '女'
              ELSE ''
              END AS sex_value
        FROM USER_DATA
    </select>
    <update id="truncateUserData">
        TRUNCATE TABLE USER_DATA
    </update>
</mapper>

また、JUnit5 DBUnitで利用するDB接続先設定の内容は、以下の通り。

package com.example.demo.mapper.ps;

import com.github.springtestdbunit.bean.DatabaseConfigBean;
import com.github.springtestdbunit.bean.DatabaseDataSourceConnectionFactoryBean;
import org.dbunit.ext.postgresql.PostgresqlDataTypeFactory;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Primary;
import org.springframework.context.annotation.PropertySource;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.PlatformTransactionManager;

import javax.sql.DataSource;

// MyBatisのテストを実行する際のDB接続定義
// @MybatisTestアノテーションでテストを実行する際、
// Spring Bootアプリケーションが起動するようにする。
// その際、com.example.demo.mapper.oraフォルダ下のインスタンス
// (UserDataMapper)のみがDIで使用できるようになる。
@SpringBootApplication
@PropertySource(value = {"classpath:test.properties"})
public class DemoTestPsConfig {

    /**
     * PostgreSQLのデータソースプロパティ(UT)を生成する.
     * @return PostgreSQLのデータソースプロパティ(UT)
     */
    @Bean(name = {"datasourcePsProperties"})
    @Primary
    @ConfigurationProperties(prefix = "spring.datasourceut-ps")
    public DataSourceProperties datasourcePsProperties() {
        return new DataSourceProperties();
    }

    /**
     * PostgreSQLのデータソース(UT)を生成する.
     * @param properties PostgreSQLのデータソースプロパティ(UT)
     * @return PostgreSQLのデータソース(UT)
     */
    @Bean(name = {"dataSourcePs"})
    @Primary
    public DataSource datasourcePs(
            @Qualifier("datasourcePsProperties") DataSourceProperties properties) {
        return properties.initializeDataSourceBuilder().build();
    }

    /**
     * PostgreSQLのトランザクションマネージャ(UT)を生成する.
     * @param dataSourcePs PostgreSQLのデータソース(UT)
     * @return PostgreSQLのトランザクションマネージャ(UT)
     */
    @Bean(name = {"txManagerPs"})
    @Primary
    public PlatformTransactionManager txManagerPs(
            @Qualifier("dataSourcePs") DataSource dataSourcePs) {
        return new DataSourceTransactionManager(dataSourcePs);
    }

    /**
     * PostgreSQLのDB接続設定(UT)を生成する.
     * @return PostgreSQLのDB接続設定(UT)
     */
    @Bean(name = {"dbUnitDatabaseConfigPs"})
    public DatabaseConfigBean dbUnitDatabaseConfigPs() {
        DatabaseConfigBean bean = new DatabaseConfigBean();
        bean.setAllowEmptyFields(true);
        bean.setDatatypeFactory(new PostgresqlDataTypeFactory());
        return bean;
    }

    /**
     * PostgreSQLのデータソースコネクションファクトリ(UT)を生成する.
     * @param dbUnitDatabaseConfigPs PostgreSQLのDB接続設定(UT)
     * @param dataSourcePs           PostgreSQLのデータソース(UT)
     * @return PostgreSQLのデータソースコネクションファクトリ(UT)
     */
    @Bean(name = {"dbUnitDatabaseConnectionPs"})
    public DatabaseDataSourceConnectionFactoryBean dbUnitDatabaseConnectionPs(
          @Qualifier("dbUnitDatabaseConfigPs") DatabaseConfigBean dbUnitDatabaseConfigPs,
          @Qualifier("dataSourcePs") DataSource dataSourcePs) {
        DatabaseDataSourceConnectionFactoryBean bean 
            = new DatabaseDataSourceConnectionFactoryBean(dataSourcePs);
        bean.setDatabaseConfig(dbUnitDatabaseConfigPs);
        return bean;
    }
}

さらに、Mapperのテストクラスの内容は以下の通りで、truncate table文とその実行前後のデータを取得している。

package com.example.demo.mapper.ps;

import com.example.demo.mapper.DemoXlsDataSetLoader;
import com.example.demo.mapper.UserData;
import com.github.springtestdbunit.DbUnitTestExecutionListener;
import com.github.springtestdbunit.TransactionDbUnitTestExecutionListener;
import com.github.springtestdbunit.annotation.DbUnitConfiguration;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mybatis.spring.boot.test.autoconfigure.MybatisTest;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase;
import org.springframework.test.context.TestExecutionListeners;
import org.springframework.test.context.support.DependencyInjectionTestExecutionListener;
import org.springframework.test.context.support.DirtiesContextTestExecutionListener;

import java.util.List;

import static org.junit.Assert.assertEquals;

// JUnit5ベースでMyBatisのテストを実行する
@MybatisTest
@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE)
@TestExecutionListeners({DependencyInjectionTestExecutionListener.class
        , DirtiesContextTestExecutionListener.class
        , TransactionDbUnitTestExecutionListener.class
        , DbUnitTestExecutionListener.class})
@DbUnitConfiguration(dataSetLoader = DemoXlsDataSetLoader.class
        , databaseConnection = {"dbUnitDatabaseConnectionPs"})
public class UserDataTruncateTestPs {

    /**
     * ユーザーデータテーブル(user_data)へアクセスするマッパー
     */
    @Autowired
    private UserDataMapperPs userDataMapperPs;

    /**
     * 各テストメソッドを実行する前に行う処理を定義する.
     */
    @BeforeEach
    public void beforeTest() {
        System.out.println();
        System.out.println("*** UserDataTruncateTestPsクラス テスト結果 start ***");
    }

    /**
     * truncate文の実行結果を検証する.
     */
    @Test
    public void userDataTest() {
        // ユーザーデータ削除する前のデータを確認
        System.out.println("*** ユーザーデータテーブル(user_data)のデータ Truncate前 ***");
        List<UserData> userDataList = userDataMapperPs.findAll();
        for (UserData userData : userDataList) {
            System.out.println(userData);
        }

        // ユーザーデータを削除
        userDataMapperPs.truncateUserData();

        // ユーザーデータ削除した後のデータを確認
        System.out.println("*** ユーザーデータテーブル(user_data)のデータ Truncate後 ***");
        userDataList = userDataMapperPs.findAll();
        System.out.println(userDataList);
        assertEquals(0, userDataList.size());
    }

    /**
     * 各テストメソッドを実行した後に行う処理を定義する.
     */
    @AfterEach
    public void afterTestClass() {
        System.out.println("*** UserDataTruncateTestPsクラス テスト結果 end ***");
        System.out.println();
    }
}

上記テストクラスの実行結果は以下の通りで、truncate table文の実行でロールバックされていることが確認できる。

<テストクラス実行前>
PostgreSQL_実行前

<テストクラスの実行>
PostgreSQL_実行

<テストクラス実行後>
PostgreSQL_実行後



「FlexClip」はテンプレートとして利用できる動画・画像・音楽などが充実した動画編集ツールだったテンプレートとして利用できるテキスト・動画・画像・音楽など(いずれも著作権フリー)が充実している動画編集ツールの一つに、「FlexCli...

SQL Serverの場合のソースコードとテスト実行結果

テスト対象となるMapperの内容は、以下の通り。

package com.example.demo.mapper.ss;

import com.example.demo.mapper.UserData;
import org.apache.ibatis.annotations.Mapper;
import java.util.List;

@Mapper
public interface UserDataMapperSs {

    /**
     * SQL Serverでユーザーデータテーブル(user_data)の全データを取得する
     * @return ユーザーデータテーブル(user_data)の全データ
     */
    List<UserData> findAll();

    /**
     * SQL Serverでユーザーデータテーブル(user_data)の全データを削除する
     */
    void truncateUserData();
}
<?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="com.example.demo.mapper.ss.UserDataMapperSs">
    <resultMap id="userDataResultMap" type="com.example.demo.mapper.UserData" >
        <id column="id" property="id" jdbcType="BIGINT" />
        <result column="name" property="name" jdbcType="VARCHAR" />
        <result column="birthY" property="birthY" jdbcType="VARCHAR" />
        <result column="birthM" property="birthM" jdbcType="VARCHAR" />
        <result column="birthD" property="birthD" jdbcType="VARCHAR" />
        <result column="sex" property="sex" jdbcType="VARCHAR" />
        <result column="memo" property="memo" jdbcType="VARCHAR" />
        <result column="sex_value" property="sex_value" jdbcType="VARCHAR" />
    </resultMap>
    <select id="findAll" resultMap="userDataResultMap">
        SELECT
              id
            , name
            , birth_year as birthY
            , birth_month as birthM
            , birth_day as birthD
            , sex
            , memo
            , CASE sex
              WHEN '1' THEN '男'
              WHEN '2' THEN '女'
              ELSE ''
              END AS sex_value
        FROM dbo.USER_DATA
    </select>
    <update id="truncateUserData">
        TRUNCATE TABLE dbo.USER_DATA
    </update>
</mapper>

また、JUnit5 DBUnitで利用するDB接続先設定の内容は、以下の通り。

package com.example.demo.mapper.ss;

import com.github.springtestdbunit.bean.DatabaseConfigBean;
import com.github.springtestdbunit.bean.DatabaseDataSourceConnectionFactoryBean;
import org.dbunit.ext.mssql.MsSqlDataTypeFactory;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Primary;
import org.springframework.context.annotation.PropertySource;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.PlatformTransactionManager;

import javax.sql.DataSource;

// MyBatisのテストを実行する際のDB接続定義
// @MybatisTestアノテーションでテストを実行する際、
// Spring Bootアプリケーションが起動するようにする。
// その際、com.example.demo.mapper.oraフォルダ下のインスタンス
// (UserDataMapper)のみがDIで使用できるようになる。
@SpringBootApplication
@PropertySource(value = {"classpath:test.properties"})
public class DemoTestSsConfig {

    /**
     * SQLServerのデータソースプロパティ(UT)を生成する.
     * @return SQLServerのデータソースプロパティ(UT)
     */
    @Bean(name = {"datasourceSsProperties"})
    @Primary
    @ConfigurationProperties(prefix = "spring.datasourceut-ss")
    public DataSourceProperties datasourceSsProperties() {
        return new DataSourceProperties();
    }

    /**
     * SQLServerのデータソース(UT)を生成する.
     * @param properties SQLServerのデータソースプロパティ(UT)
     * @return SQLServerのデータソース(UT)
     */
    @Bean(name = {"dataSourceSs"})
    @Primary
    public DataSource datasourceSs(
            @Qualifier("datasourceSsProperties") DataSourceProperties properties) {
        return properties.initializeDataSourceBuilder().build();
    }

    /**
     * SQLServerのトランザクションマネージャ(UT)を生成する.
     * @param dataSourceSs SQLServerのデータソース(UT)
     * @return SQLServerのトランザクションマネージャ(UT)
     */
    @Bean(name = {"txManagerSs"})
    @Primary
    public PlatformTransactionManager txManagerSs(
            @Qualifier("dataSourceSs") DataSource dataSourceSs) {
        return new DataSourceTransactionManager(dataSourceSs);
    }

    /**
     * SQLServerのDB接続設定(UT)を生成する.
     * @return SQLServerのDB接続設定(UT)
     */
    @Bean(name = {"dbUnitDatabaseConfigSs"})
    public DatabaseConfigBean dbUnitDatabaseConfigSs() {
        DatabaseConfigBean bean = new DatabaseConfigBean();
        bean.setAllowEmptyFields(true);
        bean.setDatatypeFactory(new MsSqlDataTypeFactory());
        return bean;
    }

    /**
     * SQLServerのデータソースコネクションファクトリ(UT)を生成する.
     * @param dbUnitDatabaseConfigSs SQLServerのDB接続設定(UT)
     * @param dataSourceSs           SQLServerのデータソース(UT)
     * @return SQLServerのデータソースコネクションファクトリ(UT)
     */
    @Bean(name = {"dbUnitDatabaseConnectionSs"})
    public DatabaseDataSourceConnectionFactoryBean dbUnitDatabaseConnectionSs(
          @Qualifier("dbUnitDatabaseConfigSs") DatabaseConfigBean dbUnitDatabaseConfigSs,
          @Qualifier("dataSourceSs") DataSource dataSourceSs) {
        DatabaseDataSourceConnectionFactoryBean bean 
            = new DatabaseDataSourceConnectionFactoryBean(dataSourceSs);
        bean.setDatabaseConfig(dbUnitDatabaseConfigSs);
        return bean;
    }
}

さらに、Mapperのテストクラスの内容は以下の通りで、truncate table文とその実行前後のデータを取得している。

package com.example.demo.mapper.ss;

import com.example.demo.mapper.DemoXlsDataSetLoader;
import com.example.demo.mapper.UserData;
import com.github.springtestdbunit.DbUnitTestExecutionListener;
import com.github.springtestdbunit.TransactionDbUnitTestExecutionListener;
import com.github.springtestdbunit.annotation.DbUnitConfiguration;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mybatis.spring.boot.test.autoconfigure.MybatisTest;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase;
import org.springframework.test.context.TestExecutionListeners;
import org.springframework.test.context.support.DependencyInjectionTestExecutionListener;
import org.springframework.test.context.support.DirtiesContextTestExecutionListener;

import java.util.List;

import static org.junit.Assert.assertEquals;

// JUnit5ベースでMyBatisのテストを実行する
@MybatisTest
@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE)
@TestExecutionListeners({DependencyInjectionTestExecutionListener.class
        , DirtiesContextTestExecutionListener.class
        , TransactionDbUnitTestExecutionListener.class
        , DbUnitTestExecutionListener.class})
@DbUnitConfiguration(dataSetLoader = DemoXlsDataSetLoader.class
        , databaseConnection = {"dbUnitDatabaseConnectionSs"})
public class UserDataTruncateTestSs {

    /**
     * ユーザーデータテーブル(user_data)へアクセスするマッパー
     */
    @Autowired
    private UserDataMapperSs userDataMapperSs;

    /**
     * 各テストメソッドを実行する前に行う処理を定義する.
     */
    @BeforeEach
    public void beforeTest() {
        System.out.println();
        System.out.println("*** UserDataTruncateTestSsクラス テスト結果 start ***");
    }

    /**
     * truncate文の実行結果を検証する.
     */
    @Test
    public void userDataTest() {
        // ユーザーデータ削除する前のデータを確認
        System.out.println("*** ユーザーデータテーブル(user_data)のデータ Truncate前 ***");
        List<UserData> userDataList = userDataMapperSs.findAll();
        for (UserData userData : userDataList) {
            System.out.println(userData);
        }

        // ユーザーデータを削除
        userDataMapperSs.truncateUserData();

        // ユーザーデータ削除した後のデータを確認
        System.out.println("*** ユーザーデータテーブル(user_data)のデータ Truncate後 ***");
        userDataList = userDataMapperSs.findAll();
        System.out.println(userDataList);
        assertEquals(0, userDataList.size());
    }

    /**
     * 各テストメソッドを実行した後に行う処理を定義する.
     */
    @AfterEach
    public void afterTestClass() {
        System.out.println("*** UserDataTruncateTestSsクラス テスト結果 end ***");
        System.out.println();
    }
}

上記テストクラスの実行結果は以下の通りで、truncate table文の実行でロールバックされていることが確認できる。

<テストクラス実行前>
SQLServer_実行前

<テストクラスの実行>
SQLServer_実行

<テストクラス実行後>
SQLServer_実行後

要点まとめ

  • JUnit5 DBUnitを利用して、truncate table文を実行すると、OracleとMySQLの場合はコミットされ、PostgreSQLとSQL Serverの場合はロールバックされることが確認できる。