テストコードを作成する-SpringBoot入門⑦

Todo(SpringBoot):サムネイル画像7 Todoアプリ(SpringBoot)

前回は Repository を作成しました。

今回は Repository のテストコードを作成します。

テストコードとは?

作成したプログラムが期待した通りに動作するか確認するためのコードです。

論理的には、あらゆる処理がテスト対象になりますが、細部までテストするには途方もない時間がかかります。

故に、大抵は重要なポイントを幾つか選定して、その箇所を重点的にテストすることが多い印象です。

Todo 開発では Repository と Service に対してテストコードを作成します。

事前準備

下記2つが無いとテストできないので準備します。

  1. テスト実行時の設定ファイル
  2. テストデータ

1. 設定ファイル

下記手順で設定ファイルを作成します。

  1. test フォルダ内に resources フォルダを作成
  2. resources フォルダ内に application-test.properties を作成
SpringBootでToDo開発7:Repository のテスト準備.
resources 配下に作成

設定ファイルの内容は以下です。

# ロードする sql ファイルのパス
spring.flyway.locations=filesystem:src/main/resources/db/migration/table

# SQLのログを出力
logging.level.org.hibernate.SQL=debug
logging.level.org.hibernate.type=trace
logging.level.org.hibernate.orm.jdbc.bind=trace
logging.level.org.hibernate.orm.jdbc.extract=trace
spring.jpa.show-sql=true

テストコード実行前にロードしておく SQL テーブルと、データベースのログに関する設定を記載しています。

ここら辺の設定項目に関しては、公式サイトに記載があることが殆どなので、それに従っています。

Spring Boot JPA で MySQL データアクセス - 公式サンプルコード
Spring Boot の概要から各機能の詳細までが網羅された公式リファレンスドキュメントです。開発者が最初に読むべきドキュメントです。

2. テストデータ作成

下記手順で設定ファイルを作成します。

  1. resources フォルダ内に db フォルダを作成
  2. db フォルダ内に migration フォルダを作成
  3. migration フォルダ内に repository フォルダを作成
  4. 下記記載の GitHub からテストデータをコピペ
SpringBootTodoServer/src/test/resources/db/migration/repository at main · o-zack-0390/SpringBootTodoServer
Todo データを処理するSpringプロジェクト. Contribute to o-zack-0390/SpringBootTodoServer development by creating an...
SpringBootでToDo開発7:Repository のテスト準備.2
resources 配下に作成

ファイル数が多く、テストデータを全て載せると超見づらくなるので、上記の GitHub からコピペしていただければと思います。

各フォルダ内のテストデータは4種類用意しています。

  1. common.sql
  2. read.sql
  3. update.sql
  4. delete.sql

それぞれ下記役割を担っています。

  1. 参照先テーブルのデータ
  2. 取得対象のデータ
  3. 更新対象のデータ
  4. 削除対象のデータ

なお、場合によっては不要なファイルもあるため、そのケースではファイル自体を作成していません。

Dto の追加作成

main/…/dto/response フォルダ内に下記ファイルを作成してください。

  • ResponseTodoDto.java
SpringBootでToDo開発7:Repository のテスト準備.3
dto/response 配下に作成.

ファイル内容は下記のとおりです。

package com.ozack.todoapp.dto.response;

import java.util.List;

import com.ozack.todoapp.repository.entity.Category;

/* フロントエンド側にレスポンスする Todo データ */
public record ResponseTodoDto(
    Long id,
    String title,
    Boolean isCheck,
    List<Category> categories
){}

この Dto は、テストコードの TodoRepositoryTest.java から呼び出します。

テストコード作成

test フォルダ内にも repository フォルダを作成します。

さらに、repository フォルダ内に下記ファイルを作成します。

  1. AuthorityRepository.java
  2. CategoryRepositoryTest.java
  3. TodoCategoryRepositoryTest.java
  4. TodoRepositoryTest.java
  5. UserRepositoryTest.java

これらファイルをテストコードへ変身させるために中身を記載していきます。

SpringBootでToDo開発6:Repository のテストコードを作成.
テストコードを作成.

コード内容は以下のとおりです。

package com.ozack.todoapp.repository;

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

import java.util.ArrayList;
import java.util.List;

import org.junit.jupiter.api.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.context.jdbc.Sql;
import org.springframework.transaction.annotation.Transactional;

import com.ozack.todoapp.repository.entity.Authority;

/* AuthorityRepository のテストコード */
@SpringBootTest
@ActiveProfiles("test")
@Transactional
public class AuthorityRepositoryTest {

    private final Logger logger = LoggerFactory.getLogger(this.getClass());

    @Autowired
    AuthorityRepository authorityRepository;

    /* 1. 全ての Authority データの取得を試みる. */
    @Test
    @Sql("/db/migration/repository/authority/read.sql")
    public void test_findAll() {

        List<Authority> expected = new ArrayList<>();
        expected.add(new Authority(1L, "authority-name-1"));
        expected.add(new Authority(2L, "authority-name-2"));

        // データ取得時のレスポンスタイムを計測
        long start = System.currentTimeMillis();
        List<Authority> actual = authorityRepository.findAll();
        logger.info("Elapsed read time -->" + (System.currentTimeMillis() - start));

        assertEquals(expected.get(0).getId(), actual.get(0).getId());
        assertEquals(expected.get(0).getName(), actual.get(0).getName());
        assertEquals(expected.get(1).getId(), actual.get(1).getId());
        assertEquals(expected.get(1).getName(), actual.get(1).getName());
    }

    /* 2. データの登録を試みる */
    @Test
    public void test_insert() {

        Authority expected = new Authority(
            null,
            "authority-name-1"
        );

        // レスポンスタイムを計測
        long start = System.currentTimeMillis();
        Authority savedEntity = authorityRepository.save(expected);
        logger.info("Elapsed insert time -->" + (System.currentTimeMillis() - start));

        Authority actual = authorityRepository.findById(savedEntity.getId()).orElse(null);
        assertNotNull(actual.getId());
        assertEquals(expected.getName(), actual.getName());
    }

    /* 3. データの更新を試みる */
    @Test
    @Sql("/db/migration/repository/authority/update.sql")
    public void test_update() {

        Authority expected = new Authority(
            1L,
            "authority-name-2"
        );

        // レスポンスタイムを計測
        long start = System.currentTimeMillis();
        Authority savedEntity = authorityRepository.save(expected);
        logger.info("Elapsed update time -->" + (System.currentTimeMillis() - start));

        Authority actual = authorityRepository.findById(savedEntity.getId()).orElse(null);
        assertEquals(expected.getId(), actual.getId());
        assertEquals(expected.getName(), actual.getName());
    }

    /* 4. データの削除を試みる */
    @Test
    @Sql("/db/migration/repository/authority/delete.sql")
    public void test_deleteById() {

        Long id = 1L;

        // レスポンスタイムを計測
        long start = System.currentTimeMillis();
        authorityRepository.deleteById(id);
        logger.info("Elapsed delete time -->" + (System.currentTimeMillis() - start));

        Authority actual = authorityRepository.findById(id).orElse(null);
        assertEquals(null, actual);
    }

}

/*
    想定場面
    1. 全ての Authority データの取得を試みる.
    2. データの登録を試みる.
    3. データの更新を試みる.
    4. データの削除を試みる.

    期待処理
    1. Authority データを全て取得.
    2. 該当データを登録
    4. 該当データを更新
    3. 該当データを削除
*/
package com.ozack.todoapp.repository;

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

import java.util.ArrayList;
import java.util.List;

import org.junit.jupiter.api.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.context.jdbc.Sql;
import org.springframework.transaction.annotation.Transactional;

import com.ozack.todoapp.repository.entity.Category;

/* CategoryRepository のテストコード */
@SpringBootTest
@ActiveProfiles("test")
@Transactional
public class CategoryRepositoryTest {

    private final Logger logger = LoggerFactory.getLogger(this.getClass());

    @Autowired
    CategoryRepository categoryRepository;

    /* 1. 全ての Category データの取得を試みる. */
    @Test
    @Sql("/db/migration/repository/category/read.sql")
    public void test_findAll() {

        List<Category> expected = new ArrayList<>();
        expected.add(new Category(1L, "category-name-1"));
        expected.add(new Category(2L, "category-name-2"));

        // データ取得時のレスポンスタイムを計測
        long start = System.currentTimeMillis();
        List<Category> actual = categoryRepository.findAll();
        logger.info("Elapsed read time -->" + (System.currentTimeMillis() - start));

        assertEquals(expected.get(0).getId(), actual.get(0).getId());
        assertEquals(expected.get(0).getName(), actual.get(0).getName());
        assertEquals(expected.get(1).getId(), actual.get(1).getId());
        assertEquals(expected.get(1).getName(), actual.get(1).getName());
    }

    /* 2. データの登録を試みる */
    @Test
    public void test_insert() {

        Category expected = new Category(
            null,
            "category-name-1"
        );

        // レスポンスタイムを計測
        long start = System.currentTimeMillis();
        Category savedEntity = categoryRepository.save(expected);
        logger.info("Elapsed insert time -->" + (System.currentTimeMillis() - start));

        Category actual = categoryRepository.findById(savedEntity.getId()).orElse(null);
        assertNotNull(actual.getId());
        assertEquals(expected.getName(), actual.getName());
    }

    /* 3. データの更新を試みる */
    @Test
    @Sql("/db/migration/repository/category/update.sql")
    public void test_update() {

        Category expected = new Category(
            1L,
            "category-name-2"
        );

        // レスポンスタイムを計測
        long start = System.currentTimeMillis();
        Category savedEntity = categoryRepository.save(expected);
        logger.info("Elapsed update time -->" + (System.currentTimeMillis() - start));

        Category actual = categoryRepository.findById(savedEntity.getId()).orElse(null);
        assertEquals(expected.getId(), actual.getId());
        assertEquals(expected.getName(), actual.getName());
    }

    /* 4. データの削除を試みる */
    @Test
    @Sql("/db/migration/repository/category/delete.sql")
    public void test_deleteById() {

        Long id = 1L;

        // レスポンスタイムを計測
        long start = System.currentTimeMillis();
        categoryRepository.deleteById(id);
        logger.info("Elapsed delete time -->" + (System.currentTimeMillis() - start));

        Category actual = categoryRepository.findById(id).orElse(null);
        assertEquals(null, actual);
    }

}

/*
    想定場面
    1. 全ての Category データの取得を試みる.
    2. データの登録を試みる.
    3. データの更新を試みる.
    4. データの削除を試みる.

    期待処理
    1. Category データを全て取得.
    2. 該当データを登録
    4. 該当データを更新
    3. 該当データを削除
*/
package com.ozack.todoapp.repository;

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

import org.junit.jupiter.api.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.context.jdbc.Sql;
import org.springframework.transaction.annotation.Transactional;

import com.ozack.todoapp.repository.entity.TodoCategory;

/* TodoCategoryRepository のテストコード */
@SpringBootTest
@ActiveProfiles("test")
@Transactional
public class TodoCategoryRepositoryTest {

    private final Logger logger = LoggerFactory.getLogger(this.getClass());

    @Autowired
    TodoCategoryRepository todoCategoryRepository;

    /* 1. データの登録を試みる */
    @Test
    @Sql("/db/migration/repository/todocategory/common.sql")
    public void test_insert() {

        TodoCategory expected = new TodoCategory(
            null,
            1L,
            1L
        );

        // レスポンスタイムを計測
        long start = System.currentTimeMillis();
        TodoCategory savedEntity = todoCategoryRepository.save(expected);
        logger.info("Elapsed insert time -->" + (System.currentTimeMillis() - start));

        TodoCategory actual = todoCategoryRepository.findById(savedEntity.getId()).orElse(null);
        assertNotNull(actual.getId());
        assertEquals(expected.getTodoId(), actual.getTodoId());
        assertEquals(expected.getCategoryId(), actual.getCategoryId());
    }

    /* 2. データの更新を試みる. */
    @Test
    @Sql({"/db/migration/repository/todocategory/common.sql", "/db/migration/repository/todocategory/update.sql"})
    public void test_update() {

        TodoCategory expected = new TodoCategory(
            1L,
            1L,
            2L
        );

        // レスポンスタイムを計測
        long start = System.currentTimeMillis();
        TodoCategory savedEntity = todoCategoryRepository.save(expected);
        logger.info("Elapsed update time -->" + (System.currentTimeMillis() - start));

        TodoCategory actual = todoCategoryRepository.findById(savedEntity.getId()).orElse(null);
        assertEquals(expected.getId(), actual.getId());
        assertEquals(expected.getTodoId(), actual.getTodoId());
        assertEquals(expected.getCategoryId(), actual.getCategoryId());
    }

    /* 3. データの削除を試みる. */
    @Test
    @Sql({"/db/migration/repository/todocategory/common.sql", "/db/migration/repository/todocategory/delete.sql"})
    public void test_deleteById() {

        Long id = 1L;

        // レスポンスタイムを計測
        long start = System.currentTimeMillis();
        todoCategoryRepository.deleteById(id);
        logger.info("Elapsed delete time -->" + (System.currentTimeMillis() - start));

        TodoCategory actual = todoCategoryRepository.findById(id).orElse(null);
        assertEquals(null, actual);
    }

}

/*
    想定場面
    1. データの登録を試みる.
    2. データの更新を試みる.
    3. データの削除を試みる.

    期待処理
    1. 該当データを登録
    2. 該当データを更新
    3. 該当データを削除
*/
package com.ozack.todoapp.repository;

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

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;

import org.junit.jupiter.api.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.context.jdbc.Sql;
import org.springframework.transaction.annotation.Transactional;

import com.ozack.todoapp.dto.response.ResponseTodoDto;
import com.ozack.todoapp.repository.entity.Category;
import com.ozack.todoapp.repository.entity.Todo;

/* TodoRepository のテストコード */
@SpringBootTest
@ActiveProfiles("test")
@Transactional
public class TodoRepositoryTest {

    private final Logger logger = LoggerFactory.getLogger(this.getClass());

    @Autowired
    private TodoRepository todoRepository;

    /* 1. 指定の todo_id を保持する全ての Todo データの取得を試みる. */
    @Test
    @Sql({"/db/migration/repository/todo/common.sql", "/db/migration/repository/todo/read.sql"})
    public void test_findByTodoId() {

        ResponseTodoDto data1 = new ResponseTodoDto(
            1L,
            "todo-title-1",
            true,
            Arrays.asList(
                new Category(1L, "category-name-1"),
                new Category(2L, "category-name-2")
            )
        );
        ResponseTodoDto data2 = new ResponseTodoDto(
            2L,
            "todo-title-2",
            false,
            new ArrayList<>()
        );
        List<ResponseTodoDto> expected = Arrays.asList(data1, data2);

        // データ取得時のレスポンスタイムを計測
        long start = System.currentTimeMillis();
        List<Todo> todos = todoRepository.findAllByUserIdWithCategories(1L);
        logger.info("Elapsed read time -->" + (System.currentTimeMillis() - start));

        // Dto に変換
        List<ResponseTodoDto> actual = convertResponseTodoDto(todos);

        // 値を検証
        ResponseTodoDto expected1 = expected.get(1);
        ResponseTodoDto expected2 = expected.get(0);
        ResponseTodoDto actual1 = actual.get(0);
        ResponseTodoDto actual2 = actual.get(1);
        assertEquals(expected1.id(), actual1.id());
        assertEquals(expected1.title(), actual1.title());
        assertEquals(expected1.isCheck(), actual1.isCheck());
        assertEquals(0, actual1.categories().size());
        assertEquals(expected2.id(), actual2.id());
        assertEquals(expected2.title(), actual2.title());
        assertEquals(expected2.isCheck(), actual2.isCheck());
        assertEquals(
            expected2.categories().get(0).getId(),
            actual2.categories().get(0).getId()
        );
        assertEquals(
            expected2.categories().get(0).getName(),
            actual2.categories().get(0).getName()
        );
        assertEquals(
            expected2.categories().get(1).getId(),
            actual2.categories().get(1).getId()
        );
        assertEquals(
            expected2.categories().get(1).getName(),
            actual2.categories().get(1).getName()
        );
    }

    /* 2. データの登録を試みる */
    @Test
    @Sql("/db/migration/repository/todo/common.sql")
    public void test_insert() {

        Todo expected = new Todo(
            null,
            1L,
            "todo-title-1",
            true
        );

        // レスポンスタイムを計測
        long start = System.currentTimeMillis();
        Todo savedEntity = todoRepository.save(expected);
        logger.info("Elapsed insert time -->" + (System.currentTimeMillis() - start));

        Todo actual = todoRepository.findById(savedEntity.getId()).orElse(null);
        assertNotNull(actual.getId());
        assertEquals(expected.getUserId(), actual.getUserId());
        assertEquals(expected.getTitle(), actual.getTitle());
        assertEquals(expected.getIsCheck(), actual.getIsCheck());
    }

    /* 3. データの更新を試みる */
    @Test
    @Sql({"/db/migration/repository/todo/common.sql", "/db/migration/repository/todo/update.sql"})
    public void test_update() {

        Todo expected = new Todo(
            1L,
            1L,
            "todo-title-2",
            false
        );

        // レスポンスタイムを計測
        long start = System.currentTimeMillis();
        Todo savedEntity = todoRepository.save(expected);
        logger.info("Elapsed update time -->" + (System.currentTimeMillis() - start));

        Todo actual = todoRepository.findById(savedEntity.getId()).orElse(null);
        assertEquals(expected.getId(), actual.getId());
        assertEquals(expected.getUserId(), actual.getUserId());
        assertEquals(expected.getTitle(), actual.getTitle());
        assertEquals(expected.getIsCheck(), actual.getIsCheck());
    }

    /* 4. データの削除を試みる */
    @Test
    @Sql({"/db/migration/repository/todo/common.sql", "/db/migration/repository/todo/delete.sql"})
    public void test_deleteById() {

        Long id = 1L;

        // レスポンスタイムを計測
        long start = System.currentTimeMillis();
        todoRepository.deleteById(id);
        logger.info("Elapsed delete time -->" + (System.currentTimeMillis() - start));

        Todo actual = todoRepository.findById(id).orElse(null);
        assertEquals(null, actual);
    }

    public List<ResponseTodoDto> convertResponseTodoDto(List<Todo> todos) {
        return todos.stream()
                    .map(todo -> new ResponseTodoDto(
                            todo.getId(),
                            todo.getTitle(),
                            todo.getIsCheck(),
                            todo.getTodoCategories()
                                .stream()
                                .sorted(Comparator.comparing(todoCategory -> todoCategory.getCategory().getName()))
                                .map(todoCategory -> new Category(
                                    todoCategory.getCategoryId(),
                                    todoCategory.getCategory().getName()
                                ))
                                .collect(Collectors.toList())
                    ))
                    .collect(Collectors.toList());
    }

}

/*
    想定場面
    1. 指定の todo_id を保持する全ての Todo データの取得を試みる.
    2. データの登録を試みる.
    3. データの更新を試みる.
    4. データの削除を試みる.

    期待処理
    1. 該当する Todo データを全て取得.
    2. 該当データを登録
    4. 該当データを更新
    3. 該当データを削除
*/
package com.ozack.todoapp.repository;

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

import org.junit.jupiter.api.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.context.jdbc.Sql;
import org.springframework.transaction.annotation.Transactional;

import com.ozack.todoapp.dto.response.ResponseUserDto;
import com.ozack.todoapp.repository.entity.Authority;
import com.ozack.todoapp.repository.entity.User;

/* UserRepository のテストコード */
@SpringBootTest
@ActiveProfiles("test")
@Transactional
public class UserRepositoryTest {

    private final Logger logger = LoggerFactory.getLogger(this.getClass());

    @Autowired
    private UserRepository userRepository;

    /* 1. 指定の email を保持するデータの取得を試みる. */
    @Test
    @Sql({"/db/migration/repository/user/common.sql", "/db/migration/repository/user/read.sql"})
    public void test_findByEmail() {

        ResponseUserDto expected = new ResponseUserDto(
            1L,
            "user-name-1",
            "user-email-1",
            new Authority(
                1L,
                "authority-name-1"
            )
        );

        // データ取得時のレスポンスタイムを計測
        long start = System.currentTimeMillis();
        ResponseUserDto actual = userRepository.findByEmailWithAuthority(expected.email()).orElse(null);
        logger.info("Elapsed read time -->" + (System.currentTimeMillis() - start));

        assertEquals(expected.id(), actual.id());
        assertEquals(expected.name(), actual.name());
        assertEquals(expected.email(), actual.email());
        assertEquals(expected.authority().getId(), actual.authority().getId());
        assertEquals(expected.authority().getName(), actual.authority().getName());
    }

    /* 2. データの登録を試みる */
    @Test
    @Sql("/db/migration/repository/user/common.sql")
    public void test_insert() {

        User expected = new User(
            null,
            1L,
            "user-name-1",
            "user-email-1",
            "user-password-1"
        );

        // レスポンスタイムを計測
        long start = System.currentTimeMillis();
        User savedEntity = userRepository.save(expected);
        logger.info("Elapsed insert time -->" + (System.currentTimeMillis() - start));

        User actual = userRepository.findById(savedEntity.getId()).orElse(null);
        assertNotNull(actual.getId());
        assertEquals(expected.getAuthorityId(), actual.getAuthorityId());
        assertEquals(expected.getName(), actual.getName());
        assertEquals(expected.getEmail(), actual.getEmail());
        assertEquals(expected.getPassword(), actual.getPassword());
    }

    /* 3. データの更新を試みる */
    @Test
    @Sql({"/db/migration/repository/user/common.sql", "/db/migration/repository/user/update.sql"})
    public void test_update() {

        User expected = new User(
            1L,
            2L,
            "user-name-2",
            "user-email-2",
            "user-password-2"
        );

        // レスポンスタイムを計測
        long start = System.currentTimeMillis();
        User savedEntity = userRepository.save(expected);
        logger.info("Elapsed update time -->" + (System.currentTimeMillis() - start));

        User actual = userRepository.findById(savedEntity.getId()).orElse(null);
        assertEquals(expected.getId(), actual.getId());
        assertEquals(expected.getAuthorityId(), actual.getAuthorityId());
        assertEquals(expected.getName(), actual.getName());
        assertEquals(expected.getEmail(), actual.getEmail());
        assertEquals(expected.getPassword(), actual.getPassword());
    }

    /* 4. データの削除を試みる */
    @Test
    @Sql({"/db/migration/repository/user/common.sql", "/db/migration/repository/user/delete.sql"})
    public void test_deleteById() {

        Long id = 1L;

        // レスポンスタイムを計測
        long start = System.currentTimeMillis();
        userRepository.deleteById(id);
        logger.info("Elapsed delete time -->" + (System.currentTimeMillis() - start));

        User actual = userRepository.findById(id).orElse(null);
        assertEquals(null, actual);
    }

}

/*
    想定場面
    1. 指定の email を保持する User データの取得を試みる.
    2. データの登録を試みる.
    3. データの更新を試みる.
    4. データの削除を試みる.

    期待処理
    1. 該当する User データを取得.
    2. 該当データを登録
    4. 該当データを更新
    3. 該当データを削除
*/

TodoRepositoryTest.java だけは Repository 内で Dto 変換が不可能だったため、テストコードで Dto に変換して各変数をテストしています。

仕様上 Dto 変換できない理由は前回で解説しています。

他はどれも同じような内容なので、まとめて解説します。

コードの流れを解説

どのテストコードも4つのテストをしています。

  1. データの取得
  2. データの登録
  3. データの更新
  4. データの削除

1はフロントエンド側へ渡すデータを保持する必要があるため、データの受け取り型は Dto を用いているケースもあります。

2,3,4はデータベース側に適合したデータを保持する必要があるため、データの受け取り型は全てエンティティで統一しています。

各変数のテストは、

  1. assertEquals
  2. assertNotNull

の2つだけを使用しました。

それぞれ、

  1. 値が等しいか
  2. 値が Null でないか

を検査しています。

アノテーション解説

各アノテーション(@が付いてる箇所)で何をしているか解説します。

@SpringBootTest

テストコードだと明示しています。

このアノテーションを付与すると、テスト実行時にテスト用の機能が起動します。

@ActiveProfiles

先ほど作成した、テストコード実行時にロードする設定ファイル

  • application-test.properties

を指定します。

なお、引数に指定する箇所は、-の後ろから.の間にある文字列です。

故に、下記定義となります。

@ActiveProfiles("test")

@Transactional

テストクラスに付与すると、テスト終了後にデータベースの状態がテスト開始前まで初期化されます。

本来なら、データベース操作でバグが発生した際にロールバックを実行し、エラー前の状態に戻すことが主な役割になりますが、この仕組みをテストコードで応用しています。

@Autowired

簡単に言うとクラス呼び出しです。

前回で作成した Repository をテストコードから呼び出しています。

@Test

各メソッド(関数)に対して付与しています。

このアノテーションを付与したメソッドはテスト対象として実行できるようになります。

@Sql

テスト実行前にロードする SQL ファイルを指定します。

例えば、データの取得をテストする際にロードするファイルは下記で指定しています。

@Sql({"/db/migration/repository/todo/common.sql", "/db/migration/repository/todo/read.sql"})

この場合、common.sql, read.sql がテスト直前にロードされ、データベースに反映されます。

登録・更新・削除も同じ形式で指定します。

まとめ

今回はテストコードを用いて、作成した Repository が期待どおりの処理を行うことを確認しました。

main/…/dto/response

  1. ResponseTodoDto.java

test/java/…/repository

  1. フォルダ内の全ファイル

test/resources/…/repository

  1. フォルダ内の全ファイル

プロジェクト構成は GitHub にプッシュしています。

GitHub - o-zack-0390/SpringBootTodoServer: Todo データを処理するSpringプロジェクト
Todo データを処理するSpringプロジェクト. Contribute to o-zack-0390/SpringBootTodoServer development by creating an...

次回は Service を作成します。

タイトルとURLをコピーしました