JUnit

各DB上でDML(insert,update,delete)を実行した際の挙動をJUnit5 DBUnitで試してみた

JUnit5 DBUnitを利用して、DML(insert文, update文, delete文)を実行すると、どのDB上で実行した場合でも、テスト実行後にロールバックされる。

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

前提条件

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

各DB上でtruncate文を実行した際の挙動をJUnit5 DBUnitで試してみたtruncate table文によって、テーブルの全データを削除することができるが、truncate table文を実行した後でロールバ...

また、下記記事のように、A5M2を利用して各DBに接続できていること。

A5M2を利用して各DBに接続してみたA5M2(A5:SQL Mk-2)は、SQL文の入力支援やER図作成などの機能を備えていて、Oracle、MySQL、PostgreSQ...

やってみたこと

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

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

作成したサンプルプログラムの構成は以下の通り。
サンプルプログラムの構成
なお、上記の赤枠は、前提条件のプログラムから追加・変更したプログラムである。

databaseSetupTest.xlsx、expectedDatabaseTest.xlsxは、各DB上でのテストを行うUserDataDmlTestXXX.javaで利用するデータで、テスト実行前に設定するデータをdatabaseSetupTest.xlsxで、テスト実行後の想定データを設定するデータをexpectedDatabaseTest.xlsxで、それぞれ定義している。

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

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();

    /**
     * Oracleで指定したユーザーデータテーブル(user_data)のデータを追加する
     * @param userData ユーザーデータテーブル(user_data)の追加データ
     */
    void create(UserData userData);

    /**
     * Oracleで指定したユーザーデータテーブル(user_data)のデータを更新する
     * @param userData ユーザーデータテーブル(user_data)の更新後データ
     */
    void update(UserData userData);

    /**
     * Oracleで指定したIDをもつユーザーデータテーブル(user_data)のデータを削除する
     * @param id ID
     * @return ユーザーデータテーブル(user_data)の指定したIDのデータ
     */
    void deleteById(Long id);
}
<?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>
    <insert id="create" parameterType="com.example.demo.mapper.UserData">
        INSERT INTO USER_DATA (
              id
            , name
            , birth_year
            , birth_month
            , birth_day
            , sex
            , memo
        ) VALUES (
              #{id}
            , #{name}
            , #{birthY}
            , #{birthM}
            , #{birthD}
            , #{sex}
            , #{memo,jdbcType=VARCHAR}
        )
    </insert>
    <update id="update" parameterType="com.example.demo.mapper.UserData">
        UPDATE USER_DATA SET name = #{name}, birth_year = #{birthY}
            , birth_month = #{birthM}, birth_day = #{birthD}
            , sex = #{sex}, memo = #{memo,jdbcType=VARCHAR}
        WHERE id = #{id}
    </update>
    <delete id="deleteById" parameterType="java.lang.Long">
        DELETE FROM USER_DATA WHERE id = #{id}
    </delete>
</mapper>

また、Mapperのテストクラスの内容は以下の通りで、DML(insert文, update文, delete文)実行後の結果を検証している。

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.DatabaseSetup;
import com.github.springtestdbunit.annotation.DbUnitConfiguration;
import com.github.springtestdbunit.annotation.ExpectedDatabase;
import com.github.springtestdbunit.assertion.DatabaseAssertionMode;
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;

// 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 UserDataDmlTestOra {

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

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

    /**
     * DML(insert,update,delete)文の実行結果を検証する.
     */
    @Test
    @DatabaseSetup("/com/example/demo/xls/databaseSetupTest.xlsx")
    @ExpectedDatabase(value = "/com/example/demo/xls/expectedDatabaseTest.xlsx"
        , assertionMode = DatabaseAssertionMode.NON_STRICT_UNORDERED)
    public void userDataTest() {
        // ユーザーデータ追加・更新・削除する前のデータを確認
        System.out.println("*** ユーザーデータテーブル(user_data)のデータ DML実行前 ***");
        List<UserData> userDataList = userDataMapperOra.findAll();
        for (UserData userData : userDataList) {
            System.out.println(userData);
        }
        System.out.println();

        // ユーザーデータ(ID=4)を追加
        UserData userData4 = new UserData(4, "テスト プリン4"
                , 2016, 5, 6, "1", "テスト4", "");
        userDataMapperOra.create(userData4);

        // ユーザーデータ(ID=3)を更新
        UserData userData3 = new UserData(3, "テスト プリン3更新後"
                , 2015, 4, 21, "2", "テスト3更新後", "");
        userDataMapperOra.update(userData3);

        // ユーザーデータ(ID=2)を削除
        userDataMapperOra.deleteById(2L);

        // ユーザーデータ追加・更新・削除した後のデータを確認
        System.out.println("*** ユーザーデータテーブル(user_data)のデータ DML実行後 ***");
        userDataList = userDataMapperOra.findAll();
        for (UserData userData : userDataList) {
            System.out.println(userData);
        }
    }

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

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

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

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

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

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();

    /**
     * MySQLで指定したユーザーデータテーブル(user_data)のデータを追加する
     * @param userData ユーザーデータテーブル(user_data)の追加データ
     */
    void create(UserData userData);

    /**
     * MySQLで指定したユーザーデータテーブル(user_data)のデータを更新する
     * @param userData ユーザーデータテーブル(user_data)の更新後データ
     */
    void update(UserData userData);

    /**
     * MySQLで指定したIDをもつユーザーデータテーブル(user_data)のデータを削除する
     * @param id ID
     * @return ユーザーデータテーブル(user_data)の指定したIDのデータ
     */
    void deleteById(Long id);
}
<?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>
    <insert id="create" parameterType="com.example.demo.mapper.UserData">
        INSERT INTO USER_DATA (
              id
            , name
            , birth_year
            , birth_month
            , birth_day
            , sex
            , memo
        ) VALUES (
              #{id}
            , #{name}
            , #{birthY}
            , #{birthM}
            , #{birthD}
            , #{sex}
            , #{memo,jdbcType=VARCHAR}
        )
    </insert>
    <update id="update" parameterType="com.example.demo.mapper.UserData">
        UPDATE USER_DATA SET name = #{name}, birth_year = #{birthY}
            , birth_month = #{birthM}, birth_day = #{birthD}
            , sex = #{sex}, memo = #{memo,jdbcType=VARCHAR}
        WHERE id = #{id}
    </update>
    <delete id="deleteById" parameterType="java.lang.Long">
        DELETE FROM USER_DATA WHERE id = #{id}
    </delete>
</mapper>

また、Mapperのテストクラスの内容は以下の通りで、DML(insert文, update文, delete文)実行後の結果を検証している。

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.DatabaseSetup;
import com.github.springtestdbunit.annotation.DbUnitConfiguration;
import com.github.springtestdbunit.annotation.ExpectedDatabase;
import com.github.springtestdbunit.assertion.DatabaseAssertionMode;
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;

// 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 UserDataDmlTestMs {

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

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

    /**
     * DML(insert,update,delete)文の実行結果を検証する.
     */
    @Test
    @DatabaseSetup("/com/example/demo/xls/databaseSetupTest.xlsx")
    @ExpectedDatabase(value = "/com/example/demo/xls/expectedDatabaseTest.xlsx"
            , assertionMode = DatabaseAssertionMode.NON_STRICT_UNORDERED)
    public void userDataTest() {
        // ユーザーデータ追加・更新・削除する前のデータを確認
        System.out.println("*** ユーザーデータテーブル(user_data)のデータ DML実行前 ***");
        List<UserData> userDataList = userDataMapperMs.findAll();
        for (UserData userData : userDataList) {
            System.out.println(userData);
        }
        System.out.println();

        // ユーザーデータ(ID=4)を追加
        UserData userData4 = new UserData(4, "テスト プリン4"
                , 2016, 5, 6, "1", "テスト4", "");
        userDataMapperMs.create(userData4);

        // ユーザーデータ(ID=3)を更新
        UserData userData3 = new UserData(3, "テスト プリン3更新後"
                , 2015, 4, 21, "2", "テスト3更新後", "");
        userDataMapperMs.update(userData3);

        // ユーザーデータ(ID=2)を削除
        userDataMapperMs.deleteById(2L);

        // ユーザーデータ追加・更新・削除した後のデータを確認
        System.out.println("*** ユーザーデータテーブル(user_data)のデータ DML実行後 ***");
        userDataList = userDataMapperMs.findAll();
        for (UserData userData : userDataList) {
            System.out.println(userData);
        }
    }

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

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

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

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

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



「AOMEI Partition Assistant Standard(無料)版」は便利なパーティション管理ツールだったハードディスクの記憶領域を論理的に分割し、分割された個々の領域のことを、パーティションといいます。 例えば、以下の図の場合、C/D...

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();

    /**
     * PostgreSQLで指定したユーザーデータテーブル(user_data)のデータを追加する
     * @param userData ユーザーデータテーブル(user_data)の追加データ
     */
    void create(UserData userData);

    /**
     * PostgreSQLで指定したユーザーデータテーブル(user_data)のデータを更新する
     * @param userData ユーザーデータテーブル(user_data)の更新後データ
     */
    void update(UserData userData);

    /**
     * PostgreSQLで指定したIDをもつユーザーデータテーブル(user_data)のデータを削除する
     * @param id ID
     * @return ユーザーデータテーブル(user_data)の指定したIDのデータ
     */
    void deleteById(Long id);
}
<?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>
    <insert id="create" parameterType="com.example.demo.mapper.UserData">
        INSERT INTO USER_DATA (
              id
            , name
            , birth_year
            , birth_month
            , birth_day
            , sex
            , memo
        ) VALUES (
              #{id}
            , #{name}
            , #{birthY}
            , #{birthM}
            , #{birthD}
            , #{sex}
            , #{memo,jdbcType=VARCHAR}
        )
    </insert>
    <update id="update" parameterType="com.example.demo.mapper.UserData">
        UPDATE USER_DATA SET name = #{name}, birth_year = #{birthY}
            , birth_month = #{birthM}, birth_day = #{birthD}
            , sex = #{sex}, memo = #{memo,jdbcType=VARCHAR}
        WHERE id = #{id}
    </update>
    <delete id="deleteById" parameterType="java.lang.Long">
        DELETE FROM USER_DATA WHERE id = #{id}
    </delete>
</mapper>

また、Mapperのテストクラスの内容は以下の通りで、DML(insert文, update文, delete文)実行後の結果を検証している。

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.DatabaseSetup;
import com.github.springtestdbunit.annotation.DbUnitConfiguration;
import com.github.springtestdbunit.annotation.ExpectedDatabase;
import com.github.springtestdbunit.assertion.DatabaseAssertionMode;
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;

// 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 UserDataDmlTestPs {

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

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

    /**
     * DML(insert,update,delete)文の実行結果を検証する.
     */
    @Test
    @DatabaseSetup("/com/example/demo/xls/databaseSetupTest.xlsx")
    @ExpectedDatabase(value = "/com/example/demo/xls/expectedDatabaseTest.xlsx"
            , assertionMode = DatabaseAssertionMode.NON_STRICT_UNORDERED)
    public void userDataTest() {
        // ユーザーデータ追加・更新・削除する前のデータを確認
        System.out.println("*** ユーザーデータテーブル(user_data)のデータ DML実行前 ***");
        List<UserData> userDataList = userDataMapperPs.findAll();
        for (UserData userData : userDataList) {
            System.out.println(userData);
        }
        System.out.println();

        // ユーザーデータ(ID=4)を追加
        UserData userData4 = new UserData(4, "テスト プリン4"
                , 2016, 5, 6, "1", "テスト4", "");
        userDataMapperPs.create(userData4);

        // ユーザーデータ(ID=3)を更新
        UserData userData3 = new UserData(3, "テスト プリン3更新後"
                , 2015, 4, 21, "2", "テスト3更新後", "");
        userDataMapperPs.update(userData3);

        // ユーザーデータ(ID=2)を削除
        userDataMapperPs.deleteById(2L);

        // ユーザーデータ追加・更新・削除した後のデータを確認
        System.out.println("*** ユーザーデータテーブル(user_data)のデータ DML実行後 ***");
        userDataList = userDataMapperPs.findAll();
        for (UserData userData : userDataList) {
            System.out.println(userData);
        }
    }

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

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

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

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

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

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();

    /**
     * SQL Serverで指定したユーザーデータテーブル(user_data)のデータを追加する
     * @param userData ユーザーデータテーブル(user_data)の追加データ
     */
    void create(UserData userData);

    /**
     * SQL Serverで指定したユーザーデータテーブル(user_data)のデータを更新する
     * @param userData ユーザーデータテーブル(user_data)の更新後データ
     */
    void update(UserData userData);

    /**
     * SQL Serverで指定したIDをもつユーザーデータテーブル(user_data)のデータを削除する
     * @param id ID
     * @return ユーザーデータテーブル(user_data)の指定したIDのデータ
     */
    void deleteById(Long id);
}
<?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>
    <insert id="create" parameterType="com.example.demo.mapper.UserData">
        INSERT INTO dbo.USER_DATA (
              id
            , name
            , birth_year
            , birth_month
            , birth_day
            , sex
            , memo
        ) VALUES (
              #{id}
            , #{name}
            , #{birthY}
            , #{birthM}
            , #{birthD}
            , #{sex}
            , #{memo,jdbcType=VARCHAR}
        )
    </insert>
    <update id="update" parameterType="com.example.demo.mapper.UserData">
        UPDATE dbo.USER_DATA SET name = #{name}, birth_year = #{birthY}
            , birth_month = #{birthM}, birth_day = #{birthD}
            , sex = #{sex}, memo = #{memo,jdbcType=VARCHAR}
        WHERE id = #{id}
    </update>
    <delete id="deleteById" parameterType="java.lang.Long">
        DELETE FROM dbo.USER_DATA WHERE id = #{id}
    </delete>
</mapper>

また、Mapperのテストクラスの内容は以下の通りで、DML(insert文, update文, delete文)実行後の結果を検証している。

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.DatabaseSetup;
import com.github.springtestdbunit.annotation.DbUnitConfiguration;
import com.github.springtestdbunit.annotation.ExpectedDatabase;
import com.github.springtestdbunit.assertion.DatabaseAssertionMode;
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;

// 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 UserDataDmlTestSs {

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

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

    /**
     * DML(insert,update,delete)文の実行結果を検証する.
     */
    @Test
    @DatabaseSetup("/com/example/demo/xls/databaseSetupTest.xlsx")
    @ExpectedDatabase(value = "/com/example/demo/xls/expectedDatabaseTest.xlsx"
            , assertionMode = DatabaseAssertionMode.NON_STRICT_UNORDERED)
    public void userDataTest() {
        // ユーザーデータ追加・更新・削除する前のデータを確認
        System.out.println("*** ユーザーデータテーブル(user_data)のデータ DML実行前 ***");
        List<UserData> userDataList = userDataMapperSs.findAll();
        for (UserData userData : userDataList) {
            System.out.println(userData);
        }
        System.out.println();

        // ユーザーデータ(ID=4)を追加
        UserData userData4 = new UserData(4, "テスト プリン4"
                , 2016, 5, 6, "1", "テスト4", "");
        userDataMapperSs.create(userData4);

        // ユーザーデータ(ID=3)を更新
        UserData userData3 = new UserData(3, "テスト プリン3更新後"
                , 2015, 4, 21, "2", "テスト3更新後", "");
        userDataMapperSs.update(userData3);

        // ユーザーデータ(ID=2)を削除
        userDataMapperSs.deleteById(2L);

        // ユーザーデータ追加・更新・削除した後のデータを確認
        System.out.println("*** ユーザーデータテーブル(user_data)のデータ DML実行後 ***");
        userDataList = userDataMapperSs.findAll();
        for (UserData userData : userDataList) {
            System.out.println(userData);
        }
    }

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

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

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

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

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

要点まとめ

  • JUnit5 DBUnitを利用して、DML(insert文, update文, delete文)を実行すると、どのDB上で実行した場合でも、テスト実行後にロールバックされる。