静的メソッドをモックする方法は?
-
03-07-2019 - |
質問
私はオブジェクトをモックするのは初めてですが、オブジェクトをモックするにはクラスにインターフェースを実装する必要があることを理解しています。
私が抱えている問題は、データアクセスレイヤーで静的メソッドを使用したいが、インターフェイスに静的メソッドを配置できないことです。
これを回避する最善の方法は何ですか?インスタンスメソッドを使用するだけです(これは間違っているようですが)、または別の解決策はありますか?
解決
メソッドオブジェクトパターンを使用します。これの静的インスタンスを作成し、静的メソッドで呼び出します。モックフレームワークに応じて、テスト用にサブクラス化することができるはずです。
i.e。静的メソッドを使用したクラスの場合:
private static final MethodObject methodObject = new MethodObject();
public static void doSomething(){
methodObject.doSomething();
}
そしてあなたのメソッドオブジェクトは非常にシンプルで簡単にテストできます:
public class MethodObject {
public void doSomething() {
// do your thang
}
}
他のヒント
はい、インスタンスメソッドを使用します。静的メソッドは基本的に、「この機能を実現する方法が1つあります-多態性ではありません」と言います。モッキングはポリモーフィズムに依存しています。
今、静的メソッドが使用している実装を論理的に気にしない場合、インターフェースをパラメーターとして取ることができます。 (そしておそらく、すべてを一緒に配線するための依存性注入)。
Google経由のブログでこれを行う方法の優れた例をいくつか示します。
-
クラスをインスタンスクラスにリファクタリングし、インターフェイスを実装します。
これを行いたくないと既に述べています。
-
静的クラスメンバーのデリゲートでラッパーインスタンスクラスを使用する
これを行うと、デリゲートを介して静的インターフェイスをシミュレートできます。
-
静的クラスを呼び出す保護されたメンバーでラッパーインスタンスクラスを使用する
これは、継承および拡張が可能なため、おそらくリファクタリングなしでモック/管理するのが最も簡単です。
開始点が深すぎるところでテストしようとしている可能性があります。すべてのメソッドを個別にテストするためにテストを作成する必要はありません。プライベートメソッドと静的メソッドは、パブリックメソッドを呼び出してテストし、プライベートメソッドと静的メソッドを順番に呼び出します。
では、コードは次のようになります。
public object GetData()
{
object obj1 = GetDataFromWherever();
object obj2 = TransformData(obj1);
return obj2;
}
private static object TransformData(object obj)
{
//Do whatever
}
TransformDataメソッドに対するテストを記述する必要はありません(できません)。代わりに、TransformDataで行われた作業をテストするGetDataメソッドのテストを記述します。
可能な場合はインスタンスメソッドを使用します。
インスタンスメソッドが使用できない場合は、public static Func [T、U](模擬関数の代わりに使用できる静的関数参照)を使用します。
簡単な解決策は、セッターを介して静的クラスの実装を変更できるようにすることです:
class ClassWithStatics {
private IClassWithStaticsImpl implementation = new DefaultClassWithStaticsImpl();
// Should only be invoked for testing purposes
public static void overrideImplementation(IClassWithStaticsImpl implementation) {
ClassWithStatics.implementation = implementation;
}
public static Foo someMethod() {
return implementation.someMethod();
}
}
したがって、テストのセットアップでは、モックされたインターフェイスを使用して overrideImplementation
を呼び出します。利点は、静的クラスのクライアントを変更する必要がないことです。マイナス面は、静的クラスとその実装のメソッドを繰り返す必要があるため、コードが少し重複する可能性があることです。ただし、静的メソッドでは、基本機能を提供するリガーインターフェイスを使用できる場合があります。
問題は、サードパーティのコードを使用していて、メソッドの1つから呼び出されている場合です。私たちがやったことは、オブジェクトにそれをラップし、それをdep injで渡すことを呼び出すことです。そして、ユニットテストは、それを使ってセッターを呼び出すサードパーティの静的メソッドをモックできます。