ヘッダー画像

【Java】mockitoでstaticメソッドをモックする方法

投稿 2026年3月21日 最終更新 2026年3月21日 専門用語多め

前置き

レガシーコードを触る機会がありリファクタリングしたいのはやまやまですが、リターンよりリスクのほうが高すぎるので、まずはテストコードを書こうと思いました。

その時にstaticメソッドをモックする必要があったので、その備忘録です。

前提

依存関係

JUnitとmockitoを使います。

dependencies {
  implementation(platform("org.junit:junit-bom:5.10.2"))
  testImplementation("org.junit.jupiter:junit-jupiter")
  testImplementation("org.mockito:mockito-junit-jupiter:5.11.0")
  testImplementation("org.mockito:mockito-inline:5.2.0")
}

JUnit5を使い、staticメソッドをモックをするためにmockito-inlineを入れます。

パターン

今回は下記4パターンのstaticメソッドをモックします。

クラス名 メソッド名 引数 戻り値
LegacyUtils noArgsVoid - -
LegacyUtils argsVoid -
LegacyUtils noArgsReturn -
LegacyUtils argsReturn

テスト対象クラス

staticメソッドを呼び出すテスト対象のメソッドです。

public class LegacyService {

  public void noArgsVoid() {
    LegacyUtils.noArgsVoid();
  }

  public void argsVoid() {
    LegacyUtils.argsVoid("123", "test");
  }

  public String noArgsReturn() {
    return LegacyUtils.noArgsReturn();
  }

  public String argsReturn() {
    return LegacyUtils.argsReturn("123", "test");
  }

}

モックするstaticメソッド

今回モックするstaticメソッドです。

実際に実行してしまうと例外が出る体で、実行時エラーを投げます。

これによりモックされており、中身が実行されていないかがわかります。

public class LegacyUtils {

  public static void noArgsVoid() {
    throw new RuntimeException();
  }

  public static void argsVoid(String id, String name) {
    throw new RuntimeException();
  }

  public static String noArgsReturn() {
    throw new RuntimeException();
  }

  public static String argsReturn(String id, String name) {
    throw new RuntimeException();
  }

}

テストコード

これから紹介するテストコードは、下記クラスに記載していきます。

@ExtendWith(MockitoExtension.class)
class LegacyServiceTest {
  @InjectMocks
  private LegacyService legacyService;
  // テストコードを記載
}

staticモックをするためにMockitoExtensionを使います。

引数なし戻り値なしstaticメソッドをモック

@Test
void モックしないと実体が実行され例外が投げられる() {
  // when&then
  assertThrows(RuntimeException.class, () -> legacyService.noArgsVoid());
}
@Test
void mockStaticを行うだけで実体は実行されない() {
  try (MockedStatic<LegacyUtils> mockLegacyUtils = mockStatic(LegacyUtils.class)) {
    // when&then
    assertDoesNotThrow(() -> legacyService.noArgsVoid());
  }
}
@Test
void 何もしないことを明示的にモック() {
  try (MockedStatic<LegacyUtils> mockLegacyUtils = mockStatic(LegacyUtils.class)) {
    // given
    mockLegacyUtils.when(LegacyUtils::noArgsVoid).thenAnswer(i -> null);
    // when&then
    assertDoesNotThrow(() -> legacyService.noArgsVoid());
  }
}

引数あり戻り値なしstaticメソッドをモック

@Test
void モックしないと実体が実行され例外が投げられる() {
  // when&then
  assertThrows(RuntimeException.class, () -> legacyService.argsVoid());
}
@Test
void mockStaticを行うだけで実体は実行されない() {
  try (MockedStatic<LegacyUtils> mockLegacyUtils = mockStatic(LegacyUtils.class)) {
    // when&then
    assertDoesNotThrow(() -> legacyService.argsVoid());
  }
}
@Test
void 何もしないことを明示的にモック() {
  try (MockedStatic<LegacyUtils> mockLegacyUtils = mockStatic(LegacyUtils.class)) {
    // given
    String id = anyString();
    String name = anyString();
    mockLegacyUtils.when(() -> LegacyUtils.argsVoid(id, name)).thenAnswer(i -> null);
    // when&then
    assertDoesNotThrow(() -> legacyService.argsVoid());
  }
}

引数なし戻り値ありstaticメソッドをモック

@Test
void モックしないと実体が実行され例外が投げられる() {
  // when&then
  assertThrows(RuntimeException.class, () -> legacyService.noArgsReturn());
}
@Test
void mockStaticを行うだけで実体は実行されない() {
  try (MockedStatic<LegacyUtils> mockLegacyUtils = mockStatic(LegacyUtils.class)) {
    // when
    String result = legacyService.noArgsReturn();
    // then
    assertNull(result);
  }
}
@Test
void 戻り値を明示的にモック() {
  try (MockedStatic<LegacyUtils> mockLegacyUtils = mockStatic(LegacyUtils.class)) {
    // given
    mockLegacyUtils.when(LegacyUtils::noArgsReturn).thenReturn("success");
    // when
    String result = legacyService.noArgsReturn();
    // then
    assertEquals("success", result);
  }
}

引数あり戻り値ありstaticメソッドをモック

@Test
void モックしないと実体が実行され例外が投げられる() {
  // when&then
  assertThrows(RuntimeException.class, () -> legacyService.argsReturn());
}
@Test
void mockStaticを行うだけで実体は実行されない() {
  try (MockedStatic<LegacyUtils> mockLegacyUtils = mockStatic(LegacyUtils.class)) {
    // when
    String result = legacyService.argsReturn();
    // then
    assertNull(result);
  }
}
@Test
void 戻り値を明示的にモック() {
  try (MockedStatic<LegacyUtils> mockLegacyUtils = mockStatic(LegacyUtils.class)) {
    // given
    String id = anyString();
    String name = anyString();
    mockLegacyUtils.when(() -> LegacyUtils.argsReturn(id, name)).thenReturn("success");
    // when
    String result = legacyService.argsReturn();
    // then
    assertEquals("success", result);
  }
}

まとめ

レガシーコードのリファクタリングやテストコードは骨が折れます…。

でも手を動かさないことには一向に状況は変わらないので、頑張ってテストコード書いていこうと思います。

本音ではちょっとあきらめてましたが、mockitoのおかげで無事テストが書けて良かったです。

以上、ここまで見ていただきありがとうございます。

皆さまの快適な開発ライフに、ほんの少しでもお役に立てれば幸いです。

コメント

この記事のコメントはありません。

TOP