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?

📘 Vol.10.7:Service層×JUnitテストの基本とパターン 〜トランザクション・例外処理を含むServiceロジックを正しくテストする〜

Last updated at Posted at 2025-05-25

✅ この回で学べること

  • Service層のJUnitテストの基本構成
  • DAOやDBアクセスを含むServiceメソッドのテスト手法
  • H2 Databaseを使ったインメモリテストの実装例
  • モック化と実DBテストの使い分けパターン

🧩 事前に準備するもの

  • JUnit(JUnit 5 or 4)
  • H2 Database(組み込みDB)
  • DAOやDBユーティリティの共通化済みの状態(Vol.10.3まで参照)

✅ テスト構成イメージ(単体テスト)

[Test] UserServiceTest
     ↓ 呼び出し
[Service] UserService
     ↓ 呼び出し
[DAO] UserDao(H2DB用の実装 or モック)

📘 例1:H2データベースを用いたテスト(実DBテスト)

✅ pom.xml(H2とJUnit依存追加)

<dependency>
  <groupId>com.h2database</groupId>
  <artifactId>h2</artifactId>
  <scope>test</scope>
</dependency>
<dependency>
  <groupId>junit</groupId>
  <artifactId>junit</artifactId>
  <version>4.13.2</version>
  <scope>test</scope>
</dependency>

✅ UserServiceTest.java

public class UserServiceTest {
    private UserService userService;
    private DataSource dataSource;

    @Before
    public void setUp() throws Exception {
        // H2 in-memory DBの初期化
        JdbcDataSource ds = new JdbcDataSource();
        ds.setURL("jdbc:h2:mem:test;DB_CLOSE_DELAY=-1");
        ds.setUser("sa");
        ds.setPassword("");
        this.dataSource = ds;

        // テーブル作成・テストデータ投入
        try (Connection conn = ds.getConnection();
             Statement stmt = conn.createStatement()) {
            stmt.execute("CREATE TABLE users (user_id INT PRIMARY KEY, username VARCHAR(100), email VARCHAR(100))");
            stmt.execute("CREATE TABLE user_roles (user_id INT, role VARCHAR(50))");
        }

        // DAOとServiceのセットアップ
        UserDao userDao = new UserDaoImpl();
        UserRoleDao userRoleDao = new UserRoleDaoImpl();
        this.userService = new UserService(userDao, userRoleDao, dataSource);
    }

    @Test
    public void testRegisterUser_success() throws Exception {
        User user = new User(1, "testuser", "test@example.com");
        userService.registerUser(user, "admin");

        try (Connection conn = dataSource.getConnection();
             PreparedStatement stmt = conn.prepareStatement("SELECT * FROM users WHERE user_id = ?")) {
            stmt.setInt(1, 1);
            ResultSet rs = stmt.executeQuery();
            assertTrue(rs.next());
            assertEquals("testuser", rs.getString("username"));
        }
    }
}

✅ Service層の例外テスト

@Test(expected = ServiceException.class)
public void testRegisterUser_rollbackOnError() throws Exception {
    User user = new User(999, "errorUser", "invalid@example.com");

    // エラー発生をシミュレーションするため、userRoleDao側にエラー仕込みなども可能

    userService.registerUser(user, "invalid-role");

    // 登録されていないことを確認(ロールバックされている)
    try (Connection conn = dataSource.getConnection();
         PreparedStatement stmt = conn.prepareStatement("SELECT * FROM users WHERE user_id = ?")) {
        stmt.setInt(1, 999);
        ResultSet rs = stmt.executeQuery();
        assertFalse(rs.next());
    }
}


✅ モックによるServiceテスト(Mockito使用)

H2を使わずにDAOをモックする場合:

@Test
public void testRegisterUser_withMockDao() throws Exception {
    UserDao userDao = Mockito.mock(UserDao.class);
    UserRoleDao userRoleDao = Mockito.mock(UserRoleDao.class);
    DataSource ds = Mockito.mock(DataSource.class);
    Connection conn = Mockito.mock(Connection.class);

    when(ds.getConnection()).thenReturn(conn);

    UserService userService = new UserService(userDao, userRoleDao, ds);

    User user = new User(2, "mockuser", "mock@example.com");
    userService.registerUser(user, "admin");

    verify(userDao).insert(conn, user);
    verify(userRoleDao).assignRole(conn, 2, "admin");
}


✅ テスト方針の選択ガイド

方法 特徴 向いているケース
H2 DBを使う 実際のSQLとDB動作を確認できる SQL検証やトランザクション検証
Mockitoでモック化 DB依存なしで高速テスト 業務ロジックの分岐やエラー処理テスト中心の場合

✅ 今回のまとめ

項目 ポイント
H2使用 実DBを使った統合に近い単体テストが可能
モック使用 DBに依存せずService層のロジックのみ検証できる
トランザクション・例外 Service層の責務としてテスト対象に含めるべき


✨ シリーズまとめ(Vol.10.x バリデーション編)


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?