web-dev-qa-db-ja.com

Mockito 2.2でWhiteboxの代わりに何を使用してフィールドを設定しますか?

Mockito 1.9.xを使用しているとき、Whiteboxを使用してフィールドの値を「注入」モックに設定していました。以下の例:

@Before
public void setUp() {

    eventHandler = new ProcessEventHandler();
    securityService = new SecurityServiceMock();
    registrationService = mock(RegistrationService.class);

    Whitebox.setInternalState(eventHandler, "registrationService", registrationService);
    Whitebox.setInternalState(eventHandler, "securityService", securityService);
}

私はこのアプローチが本当に好きですが、Mockito2.2.7にアップグレードしようとしたので、気づいた(または、むしろIDEが気づいて、何度も私にホワイトボックスを告げました)モッキートではもう見つかりませんでした。

代替として機能する1つの代替案を見つけました。それはorg.powermock.reflect.Whiteboxです。これに関する問題は、Whiteboxを使用するためだけに別の依存関係(Powermock)を取得することです。

PowermockにはWhiteboxという名前のクラスもありますが、残念ながらMockito 2.2.xで使用できないように見えます。

Whiteboxが使用できなくなったため、Mockitoに手動でフィールドを「挿入」するために使用できる代替手段はありますか?


溶液

@JeffBowmanの投稿に対する返信としてコメントを書きました。要するに、私はWhiteBoxのコードをコピーし、それを使用することを選択しました。これは、ほとんどのテストケースで使用されており、クラスには他のクラスへの依存関係がないためです。この問題を解決するための最速の道でした。

@bcodyが提案する解決策はより良い代替手段です。もしあなたがspringを使用しているなら、それはあなたが維持するための余分なコードを広告しません。私はその情報を遅らせました:(

17

Whiteboxは常にorg.mockito.internal パッケージ。メジャーバージョン番号の増分を超えて、internalの指定は、パッケージに重大な変更が加えられる可能性があることを示すものです。

テストでアクセスできないフィールドを設定するポイントにしたい場合は、setInternalStateと同じ方法で設定できます。これは、階層内のフィールドを識別し、その上でsetAccessibleを呼び出してから設定するだけです。それ。 完全なコードはgrepcodeにあります。 また、多くの テストでアクセスできない状態を設定する他の方法 を調べることもできます。

public static void setInternalState(Object target, String field, Object value) {
    Class<?> c = target.getClass();
    try {
        Field f = getFieldFromHierarchy(c, field);  // Checks superclasses.
        f.setAccessible(true);
        f.set(target, value);
    } catch (Exception e) {
        throw new RuntimeException(
            "Unable to set internal state on a private field. [...]", e);
    }
}

ただし、このような状況では、私の一般的なアドバイスはツールとの戦いをやめることです:Javaの4つのレベルのカプセル化(public、protected、package、private)は、表現しようとしている保護の程度を表現するのに必ずしも十分な粒度ではなく、よく文書化された初期化メソッドまたはコンストラクターオーバーライドを追加して、依存関係をオーバーライドする方がはるかに簡単です反射的にやろうとしています。テストをテストするクラスと同じJavaパッケージに入れると、フィールドまたはメソッド/コンストラクタをパッケージプライベートにすることもできます。これは、パラレルをセットアップする十分な理由でもあります同じJavaパッケージの2つの半分を表すソースフォルダーsrcおよびtests(など)。

この追加のメソッドまたはコンストラクターを「API汚染」として扱う人もいますが、代わりに、クラスの最も重要なコンシューマーのテストの要件にコーディングするものと考えています。手付かずの外部インターフェイスが必要な場合は、簡単に個別に定義して、必要な詳細を非表示にできます。ただし、より柔軟なコンポーネントに実際の実装またはモックの実装を直接注入する機能likeを見つけることができます。この時点で、依存性注入パターンまたはフレームワークを調べることができます。 。

7
Jeff Bowman

Spring(具体的にはspring-testライブラリ)を使用している場合は、単にReflectionTestUtils.setField の代わりに Whitebox.setInternalState

34
bcody

車輪を再発明することなく、最もクリーンで、最も最近の最も移植性の高い方法は、Apache CommonsのFieldUtilsを使用することです。 https://commons.Apache.org/proper/commons-lang/apidocs/org/Apache/commons/lang3/reflect/FieldUtils.html

あなたの質問に対する答えは

public static void setStaticFieldValue(
        @NonNull final Class<?> clz,
        @NonNull final String fieldName,
        @NonNull final Object value) throws Exception {
    final Field f = FieldUtils.getField(clz, fieldName, true);
    FieldUtils.removeFinalModifier(f);
    f.set(null, value);
}
4
foo

Mockito2.xでFieldSetterを使用できます

    import org.mockito.internal.util.reflection.FieldSetter;
 FieldSetter.setField(eventHandler,eventHandler.getClass().getDeclaredField("securityService"), securityService);
2
Murik

fest-reflect apiを使用すると、リフレクションをサポートするための使いやすい流APIなAPIを見つけることができます。これは、MockitoのWhilteboxの代替として使用するものです。

1
Priyal85