技術系TIPS
PR

Mockitoでstaticメソッドとfinalクラスをモック化する

saratogax
記事内に商品プロモーションを含む場合があります

相変わらず苦手なユニットテスト作成。

特にライブラリの呼び出し部分をモック化するのが大変だなと思う今日この頃。

モック化自体は Mockito が便利なのですが、モック化したいものが以下のようなものだとちょっと面倒ですよね。

・private メソッド
・static メソッド
・final クラス

今回は、この中から static メソッドと final クラスのモック化について紹介します。

Mockito

Mockito は Java のユニットテストのために開発されたモックフレームワークで、Kotlin で開発している時にもお世話になりました。

Kotlin の場合は Mockito-Kotlin を使う感じですね。

今回は Java になりますが、JUnit と Mockito を以下のバージョンで利用していきます。

Junit: 5.4.2
Mockito: 4.4.0

staticメソッドのモック化

static メソッドはクラスをインスタンス化せずに利用できるので、以下のように Mock アノテーションでインスタンス化したものが使えないなと悩んでいました。

@Mock
private Hoge hoge;

調べてみると、Mockito の以下のクラスを利用すれば static のメソッドをモック化することが可能なようです。

MockedStatic
Mockito.mockStatic

Hoge クラスの中身は以下の内容だと仮定します。

public class Hoge {
    public static boolean isExpired() {
        return false;
    }
}

また static メソッドをモック化する方法は大きく 2 種類ありますが、私は try を使う方が好みです。

この辺はテストロジック次第というところもありますが、スコープが明確になってわかりやすいかなっと。

Hoge.isExpired() がモック化されているのは try の中だけになります。

try (MockedStatic<Hoge> mocked = mockStatic(Hoge.class)) {
    mocked.when( () -> Hoge.isExpired() )
        .thenReturn(true);

    assertEquals(true, Hoge.isExpired());
}

try を使わない場合は、利用後に close() の呼び出しが必要です。

こちらも、Hoge.isExpired() がモック化されているのは close() の呼び出しまで。

MockedStatic<Hoge> mocked = mockStatic(Hoge.class);

mocked.when( () -> Hoge.isExpired() ).thenReturn(true);

assertEquals(true, Hoge.isExpired());

mocked.close();

finalクラスをモック化する

次に final クラスのモック化です。

以下のような final クラス Fuga をモック化してみます。

public final class Fuga {
}
@Mock
private Fuga fuga;

いざビルドして test タスクを実行してみると・・・。

org.mockito.exceptions.base.MockitoException at MockitoExtension.java:153

これだけの情報だと何がなんだかわかりませんね。

もう少し詳細なエラー内容が欲しいのですが、コンソールに出力されないのですよね。

ちょっと古いですが、以下の記事と状況が似ていたので参考に。

うーん、以下のような詳細なエラー内容はどうやったら表示できるのだろうか。

Cannot mock/spy class xxxxxxxxxx
Mockito cannot mock/spy following:
– final classes
– anonymous classes
– primitive types

ということで、下記のファイルを用意します。
(テキストファイル形式で問題ありません)

resources 配下に mockito-extensions ディレクトリがない場合は作成してください。

src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker

ファイルには 1 行だけ、以下を記載します。

これで、final クラスもモック化が可能となりました。

mock-maker-inline

まとめ

ちなみに、Mockito で利用していない when() があると、以下の Exception が発生します。

UnnecessaryStubbingException

これを解決するために参考になったのは以下のサイト。

うーん JUnit 含め、まだまだ Mockito には悩まされそうだなぁ。

JUnit5で「Please remove unnecessary stubbings or use ‘lenient’ strictness. More info: javadoc for UnnecessaryStubbingException class.」エラーが発生した場合は、クラスレベルのアノテーションに@MockitoSettings(strictness = Strictness.LENIENT)を付与すれば回避することが出来ます。

Spring Bootでmockitoを使ってテストする

Junit4 と 5 もそうですが、バージョンの組み合わせで挙動が変わるのは大変です・・・。

ABOUT ME
saratoga
saratoga
フリーランスエンジニア
仕事にも趣味にも IT を駆使するフリーランスエンジニア。技術的な TIPS や日々の生活の中で深堀りしてみたくなったことを備忘録として残していきます。
記事URLをコピーしました