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?

JUnit5 と Mockito を使ったテストコードの解説

Last updated at Posted at 2025-01-06

概要

このドキュメントでは、JUnit5 および Mockito を使用して UserController クラスをテストするコードについて解説する。各アノテーションやメソッドの役割、モックの設定方法について取り上げる。

1. アノテーションの解説

@Test

  • 役割:
    テストメソッドであることを示す。JUnit5 ではこのアノテーションが付与されたメソッドがテストとして認識される。

@ExtendWith(MockitoExtension.class)

役割:
Mockito を JUnit5 で使用するための拡張機能を提供する。
これにより、@Mock@InjectMocks アノテーションが有効になる。

@InjectMocks

役割:
テスト対象クラスのインスタンスを作成し、@Mock で作成されたモックオブジェクトを自動的に注入する。

@Mock

役割:
モックオブジェクトを作成する。 when()メソッドで動作を定義することで、特定の結果を返すように設定できる。

@DisplayName

役割:
テストケースにわかりやすい名前を付ける。実行結果レポートで表示され、テストの意図が明確になる。日本語の説明も可能である。

2. メソッド解説

when()...thenReturn()

  • 役割:
    モックオブジェクトの特定のメソッドが呼ばれたときに、指定した値を返すように設定する。
  • 例:
    when(userService.findByUserId(TEST_USER_ID)).thenReturn(Optional.empty());
    
  • 解説:
    userService.findByUserId(TEST_USER_ID) が呼ばれると、常に Optional.empty() が返る。これにより「ユーザーが見つからない」ケースをシミュレートする。

anyInt()

  • 役割:
     任意の整数値が引数として渡された場合でも、モックが反応するように設定する。
  • 例:
    when(userService.findByUserId(anyInt())).thenReturn(userEntity);
    
  • 解説:
    userService.findByUserId() が任意の整数で呼び出されても、userEntity を返す。

verify()

  • 役割:
    テスト対象メソッドが特定のメソッドを呼び出したかを検証する。
  • 例:
    verify(redirectAttributes).addFlashAttribute("flashError", "指定されたユーザーが見つかりません。");
    
  • 解説:
    テスト対象メソッドが addFlashAttribute() を呼び出したかを確認する。

verifyNoInteractions()

  • 役割:
    モックオブジェクトに対して、一切のメソッドが呼び出されていないことを検証する。
  • 例:
    verifyNoInteractions(model);
    
  • 解説:
    modelオブジェクトに対して一切の操作が行われていないことを確認する。

サンプルコード

/**
* UserControllerのテストクラス
*/
@ExtendWith(MockitoExtension.class)
public class UserControllerTest {

  @InjectMocks
  private UserController controller;

  @Mock
  private UserService userService;

  @Mock
  private RedirectAttributes redirectAttributes;

  @Mock
  private HttpSession session;

  @Mock
  private Model model;

  private static final String SHOW_TEMPLATE_PATH = "user/show";
  private static final String REDIRECT_INDEX_PATH = "redirect:/user/index";
  private static final int TEST_USER_ID = 1;
  private static final Integer RESTORE_SESSION_REQUESTED = 1;
  private static final ControllerTestHelper controllerTestHelper = new ControllerTestHelper();

  /**
   * ユーザーが見つからない場合のテストケース.
   */
  @DisplayName("ユーザーが見つからない場合のテストケース.")
  @Test
  public void testShow_UserNotFound() {
      // 準備
      when(session.getAttribute("logined_user_name")).thenReturn("テストユーザー");
      when(userService.findByUserId(TEST_USER_ID)).thenReturn(Optional.empty());

      // 実行
      String result = controller.show(TEST_USER_ID, model, session, redirectAttributes);

      // 検証
      assertEquals(REDIRECT_INDEX_PATH, result);
      verify(redirectAttributes).addFlashAttribute("flashError", "指定されたユーザーが見つかりません。");
      verify(redirectAttributes).addAttribute("restoreSession", RESTORE_SESSION_REQUESTED);
      verifyNoInteractions(model);
  }

  /**
   * ユーザーが見つかり、レコードが存在しない場合のテストケース.
   * @throws ParseException 日付の形式が間違っていた際に投げられる例外.
   */
  @DisplayName("ユーザーが見つかり、レコードが存在しない場合のテストケース.")
  @Test
  public void testShow_WithoutRecords() throws ParseException {
      // 準備
      List<RecordListDto> emptyRecordList = new ArrayList<>();
      val userEntity = Optional.ofNullable(controllerTestHelper.createTestUserEntity());
      when(userService.findByUserId(anyInt())).thenReturn(userEntity);
      when(userService.findResultByUserId(anyInt())).thenReturn(emptyRecordList);

      // 実行
      String result = controller.show(TEST_USER_ID, model, session, redirectAttributes);

      // 検証
      assertEquals(SHOW_TEMPLATE_PATH, result);
      verify(model).addAttribute("user", userEntity.get());
      verify(model).addAttribute("hasRecordList", false);
  }

  /**
   * ユーザーが見つかり、レコードが存在する場合のテストケース.
   * @throws ParseException 日付の形式が間違っていた際に投げられる例外.
   */
  @DisplayName("ユーザーが見つかり、レコードが存在する場合のテストケース.")
  @Test
  public void testShow_WithRecords() throws ParseException {
      // 準備
      val recordList = controllerTestHelper.createTestRecordList();
      val userEntity = Optional.ofNullable(controllerTestHelper.createTestUserEntity());
      when(userService.findByUserId(anyInt())).thenReturn(userEntity);
      when(userService.findResultByUserId(anyInt())).thenReturn(recordList);

      // 実行
      String result = controller.show(TEST_USER_ID, model, session, redirectAttributes);

      // 検証
      assertEquals(SHOW_TEMPLATE_PATH, result);
      verify(model).addAttribute("user", userEntity.get());
      verify(model).addAttribute("hasRecordList", true);
  }
}

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?