【Java】Mockitoでインスタンスメソッドをモックする方法
投稿 2026年4月18日
最終更新 2026年4月18日
専門用語多め
前置き
レガシーコードを触る機会がありリファクタリングしたいのはやまやまですが、リターンよりリスクのほうが高すぎるので、まずはテストコードを書こうと思いました。
内容的には前回のstaticメソッドのモックの続きで、今回はメソッド内でインスタンス生成をしているクラスのメソッドをモックします。
2026年3月21日
前提
依存関係
Java17でJUnit5と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")
}
パターン
今回は下記4パターンのメソッドをモックします。
| クラス名 | メソッド名 | 引数 | 戻り値 |
|---|---|---|---|
| LegacyRepository | noArgsVoid | - | - |
| LegacyRepository | argsVoid | ● | - |
| LegacyRepository | noArgsReturn | - | ● |
| LegacyRepository | argsReturn | ● | ● |
テスト対象クラス
クラスのインスタンスを生成して、メソッドを呼び出すテスト対象のメソッドです。
public class LegacyService {
public void noArgsVoid() {
LegacyRepository repository = new LegacyRepository();
repository.noArgsVoid();
}
public void argsVoid() {
LegacyRepository repository = new LegacyRepository();
repository.argsVoid("123", "test");
}
public String noArgsReturn() {
LegacyRepository repository = new LegacyRepository();
return repository.noArgsReturn();
}
public String argsReturn() {
LegacyRepository repository = new LegacyRepository();
return repository.argsReturn("123", "test");
}
}
モックするインスタンスメソッド
今回モックするインスタンスメソッドです。
実際に実行してしまうと例外が出る体で、実行時エラーを投げます。
これによりモックされており、中身が実行されていないかがわかります。
public class LegacyRepository {
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;
// テストコードを記載
}
引数なし戻り値なしインスタンスメソッドをモック
@Test
void モックしないと実体が実行され例外が投げられる() {
// when&then
assertThrows(RuntimeException.class, () -> legacyService.noArgsVoid());
}
@Test
void mockConstructionを行うだけで実体は実行されない() {
try (MockedConstruction<LegacyRepository> mockLegacyRepository = mockConstruction(LegacyRepository.class)) {
// when&then
assertDoesNotThrow(() -> legacyService.noArgsVoid());
}
}
@Test
void 何もしないことを明示的にモック() {
try (MockedConstruction<LegacyRepository> mockLegacyRepository = mockConstruction(LegacyRepository.class,
(mock, context) -> {
// given
doNothing().when(mock).noArgsVoid();
})) {
// when&then
assertDoesNotThrow(() -> legacyService.noArgsVoid());
}
}
引数あり戻り値なしインスタンスメソッドをモック
@Test
void モックしないと実体が実行され例外が投げられる() {
// when&then
assertThrows(RuntimeException.class, () -> legacyService.argsVoid());
}
@Test
void mockConstructionを行うだけで実体は実行されない() {
try (MockedConstruction<LegacyRepository> mockLegacyRepository = mockConstruction(LegacyRepository.class)) {
// when&then
assertDoesNotThrow(() -> legacyService.argsVoid());
}
}
@Test
void 何もしないことを明示的にモック() {
try (MockedConstruction<LegacyRepository> mockLegacyRepository = mockConstruction(LegacyRepository.class,
(mock, context) -> {
// given
doNothing().when(mock).argsVoid(anyString(), anyString());
})) {
// when&then
assertDoesNotThrow(() -> legacyService.argsVoid());
}
}
引数なし戻り値ありインスタンスメソッドをモック
@Test
void モックしないと実体が実行され例外が投げられる() {
// when&then
assertThrows(RuntimeException.class, () -> legacyService.noArgsReturn());
}
@Test
void mockConstructionを行うだけで実体は実行されない() {
try (MockedConstruction<LegacyRepository> mockLegacyRepository = mockConstruction(LegacyRepository.class)) {
// when
String result = legacyService.noArgsReturn();
// then
assertNull(result);
}
}
@Test
void 戻り値を明示的にモック() {
try (MockedConstruction<LegacyRepository> mockLegacyRepository = mockConstruction(LegacyRepository.class,
(mock, context) -> {
// given
when(mock.noArgsReturn()).thenReturn("success");
})) {
// when
String result = legacyService.noArgsReturn();
// then
assertEquals("success", result);
}
}
引数あり戻り値ありインスタンスメソッドをモック
@Test
void モックしないと実体が実行され例外が投げられる() {
// when&then
assertThrows(RuntimeException.class, () -> legacyService.argsReturn());
}
@Test
void mockConstructionを行うだけで実体は実行されない() {
try (MockedConstruction<LegacyRepository> mockLegacyRepository = mockConstruction(LegacyRepository.class)) {
// when
String result = legacyService.argsReturn();
// then
assertNull(result);
}
}
@Test
void 戻り値を明示的にモック() {
try (MockedConstruction<LegacyRepository> mockLegacyRepository = mockConstruction(LegacyRepository.class,
(mock, context) -> {
// given
when(mock.argsReturn(anyString(), anyString())).thenReturn("success");
})) {
// when
String result = legacyService.argsReturn();
// then
assertEquals("success", result);
}
}
まとめ
レガシーコードのリファクタリングやテストコードは骨が折れます…。
でも手を動かさないことには一向に状況は変わらないので、頑張ってテストコード書いていこうと思います。
本音ではちょっとあきらめてましたが、Mockitoのおかげで無事テストが書けて良かったです。
以上、ここまで見ていただきありがとうございます。
皆さまの快適な開発ライフに、ほんの少しでもお役に立てれば幸いです。