🐞

Repositoryクラス、ServiceクラスのJUnitを使った単体テストについて。

2025/01/27に公開

はじめに

  • Springboot初学者です。
  • JUnitを使ったテストを実装していますが、理解が不足しているので理解を深めるためにアウトプットします。
  • 自分のためのメモ感覚でまとめていきます。
  • 今回、Controllerクラスのテストについては省略させていただきます。
  • 内容に誤り等あれば教えてください。

開発環境

  • Springboot
  • JUnit

アノテーションの使い方。

  • Mock用のアノテーションは後述します。

@SpringBootTest

  • 実際のアプリケーションと同様の環境でテストを行うことができます。
  • webEnvironment=RANDOM_PORT を使用してランダムポートでサーバーを起動することに注意してください(テスト環境での競合を回避するのに便利です)

@Test

  • 各メソッドにアノテーションをつけます。そのメソッドがテストとして実行されます。

@BeforeEach, @AfterEach

  • 各テスト(@Test等)が実行される前後に実行されるメソッド。
  • JUnit4の@Before, @Afterと類似したものです。

@BeforeAll, @AfterAll

  • 全テスト(@Test等)が実行される前後に実行されるメソッド。
  • JUnit 4の@BeforeClassと類似したものです。
  • 基本的にstaticでないといけない。

@Sql("/test.sql")

  • クラスの前にアノテーションをつけた場合は全テスト実行に前に実行される。
  • 各テストの前にアノテーションをつけた場合は各テスト実行に前に実行される。
  • /test/resouces/の下に配置されたSQLファイルを呼び出す。
  • 複数のSQLファイルを実行することもできる。
@Sql({"/test.sql", "/test-user-data.sql"})

@Transactional

  • テストメソッドに @Transactional アノテーションを付けると、トランザクション内でテストが実行され、デフォルトでは、テストの完了後に自動的にロールバックされます。
  • テストクラスに @Transactional アノテーションが付けられている場合、そのクラス階層内の各テストメソッドはトランザクション内で実行されます。

@DisplayName

  • @DisplayNameをつけると、テスト実行時に実行名が表示される。
    @Test
    @DisplayName("User情報が削除できているか確認するテスト。")
    void testDelete() {
  • ログへの出力結果。
testDelete(com.example.demo.controller.UserControllerTest),false,1,false,2,Userの退会処理を確認するテスト。,,[engine:junit-jupiter]/[class:com.example.demo.controller.UserControllerTest]/[method:testDelete()]

アサーションメソッド

アサーション 説明
asserNUll 値がnullであることを確認します。
assertEquals 二つの値が正しいことを確認します。
assertNotEquals 二つの値が異なることを確認します。

Mockとは

  • テストを行う際に実際のデータを使わずに検証を行うことができる。
  • 独立してテストを行うことができる。

Mockitoとは

  • Mockを使うためのフレームワーク。

使われるアノテーション

@Mock

  • モックオブジェクトを作成する。
@Mock
private UserRepository userRepository;

@InjectMock

  • テストの対象とするクラスの変数に付与する。
@InjectMocks
private UserService userService;

@Captor

  • ArgumentCaptorオブジェクトを生成時に使用する。
  • verifyメソッドを使用する際、引数にArgumentCaptorを渡すことができる。
ArgumentCaptor<String> fruitCaptor = ArgumentCaptor.forClass(String.class);
verify(mockCounter).countFruits(fruitCaptor.capture());

List<String> capturedFruits = fruitCaptor.getAllValues();
List<String> expectedFruits = Arrays.asList("Apple", "Banana");
assertEquals(expectedFruits, capturedFruits); 

@ExtendWith

  • 独自Extensionクラスを適応させるときに使用する。
<!-- 例:独自で作成した `CustomTestSupportExtension`クラスを適応させる。 -->
@ExtendWith(CustomTestSupportExtension.class)
class YourTest {
    CustomTestSupport support;
    @Test
    void test() {
    }
}

https://nablarch.github.io/docs/LATEST/doc/development_tools/testing_framework/guide/development_guide/06_TestFWGuide/JUnit5_Extension.html

その他のアノテーションについておすすめ記事。

https://zenn.dev/simsim/articles/4b9930dcf2308b#7.-%40webmvctest

MockMvcとは

  • コントローラーのテストをするためのツール。
  • サーバやデータベースを用意する手間を省くことができる。

使われるアノテーション

@WebMvcTest

  • Controllerのユニットテストを行うときに使用します。
  • デフォルトでは、@WebMvcTest アノテーションが付けられたテストは、Spring Security および MockMvc を自動構成します。
  • 通常、@WebMvcTest は @MockBean または @Import と組み合わせて使用されます。
  • アプリ全体をテストする場合は、このアノテーションではなく @SpringBootTest@AutoConfigureMockMvc の使用を検討する必要があります。

@AutoConfigureMockMvc

  • アプリケーション全体をテストすることができる。

@AutoConfigureMockMvc(addFilters = false)

  • Sring Security等のフィルターによりテストが実行できない時に、addFilters = falseを行うことでSpring Securityのフィルターを外すことができる。

WebMvcTestの詳細については下記のリンクを参照。

https://docs.spring.io/spring-boot/api/java/org/springframework/boot/test/autoconfigure/web/servlet/WebMvcTest.html

実装例

Repositoryクラスのテスト(Mockなし)

@SpringBootTest
@Sql("/test.sql")
@Transactional
public class UserRepositoryTest {
    @Autowired
    private UserRepository repository;

    @Test
    @DisplayName("RegisterUserFormの情報から登録処理ができているかのテスト。")
    void testInsert() {
        RegisterUserForm form = new RegisterUserForm("taro", "taro@taro", "taro");
        Integer userId = repository.insert(form);
        User user = repository.load(userId);
        assertEquals(user.getName(), "taro");
    }
}

Serviceクラスのテスト(Mockあり)

  • Serviceクラスのdelete処理で、Mockは削除できない。からverifyで確認。
@ExtendWith(MockitoExtension.class)
@Transactional
public class UserServiceTest {
    @Mock
    private UserRepository repository;

    @InjectMocks
    private UserService service;

    @Test
    @DisplayName("idからUser情報を取り出すテスト。")
    void testLoad() {
        User user = new User(1, "taro", "demo_user@example.com", "password", "hello", LocalDateTime.now(), LocalDateTime.now());
        doReturn(user).when(repository).load(1);
        User result = service.load(1);
        assertEquals(result.getName(), "taro");
        verify(repository, times(1)).load(1);
    }
}
  • doReturn(user).when(repository).load(1);
    repository.load(1)メソッドを使う時に、userを返すように指定。
  • 戻り値がnullの時は、doから始まる文を使う。
  • verify(モックインスタンス, times(想定回数)).メソッド(引数);
    テスト時にメソッドがtimesの回数だけ実行されたことを確認する。

VSCodeで簡単にテストを作成する方法。

  • ソースコードを開く。(例:UserService.java)
  • ソースコード上で右クリックし、「ソース アクション」を選択。
  • 一番上のGenerate Test...を選択。
  • テスト実行用クラスの名前を入力。
  • テストを行うメソッドを選択し、OKをクリック。
  • 簡単にテストファイルが作成される。(例:UserServiceTest.java)

参考文献

土岐 孝平. プロになるためのSpring入門ーーゼロからの開発力養成講座 Software Design plus (p. 461). (Function). Kindle Edition.
https://spring.pleiades.io/spring-boot/reference/testing/spring-boot-applications.html
https://junit.org/junit4/javadoc/4.13/org/junit/Assert.html
https://zenn.dev/simsim/articles/4b9930dcf2308b
https://qiita.com/tsukakei/items/7e48c84b96e3ebf34498
https://terasolunaorg.github.io/guideline/5.4.1.RELEASE/ja/UnitTest/ImplementsOfUnitTest/UsageOfLibraryForTest.html
https://docs.spring.io/spring-boot/api/java/org/springframework/boot/test/autoconfigure/web/servlet/WebMvcTest.html

Discussion