web-dev-qa-db-ja.com

静的メソッドでモックする方法は?

オブジェクトをモックするのは初めてですが、オブジェクトをモックするためにクラスにインターフェースを実装させる必要があることを理解しています。

私が抱えている問題は、データアクセスレイヤーで静的メソッドを使用したいのですが、静的メソッドをインターフェイスに配置できないことです。

これを回避する最良の方法は何ですか?インスタンスメソッドを使用する必要がありますか(これは間違っているようです)、または別の解決策はありますか?

34
brien

メソッドオブジェクトパターンを使用します。これの静的インスタンスを用意し、静的メソッドで呼び出します。モックフレームワークに応じて、テスト用にサブクラス化できるはずです。

つまり、静的メソッドを含むクラスでは、次のようになります。

private static final MethodObject methodObject = new MethodObject();

public static void doSomething(){
    methodObject.doSomething();
}

そしてあなたのメソッドオブジェクトは非常にシンプルで簡単にテストできます:

public class MethodObject {
    public void doSomething() {
        // do your thang
    }
}
22
Grundlefleck

私は Google経由のブログ を見つけました。

  1. クラスをインスタンスクラスにリファクタリングし、インターフェイスを実装します。

    あなたはこれをしたくないとすでに述べました。

  2. 静的クラスメンバーのデリゲートでラッパーインスタンスクラスを使用する

    これを行うと、デリゲートを介して静的インターフェイスをシミュレートできます。

  3. 静的クラスを呼び出す保護されたメンバーを持つラッパーインスタンスクラスを使用する

    継承と拡張のみが可能なため、これはおそらくリファクタリングなしでモック/管理するのが最も簡単です。

26
Rick Minerich

はい、インスタンスメソッドを使用します。静的メソッドは基本的に、「この機能を実現する方法は1つあります-多態的ではありません。」モッキングは多態性に依存しています。

ここで、静的メソッドが使用している実装に論理的に関心がない場合、それらはインターフェイスをパラメーターとして取るか、状態とまったく対話せずに機能する可能性がありますが、それ以外の場合はインスタンスを使用する必要があります(そしておそらくすべてを一緒に配線するための依存性注入)。

26
Jon Skeet

出発点が深すぎてテストしようとしている可能性があります。すべてのメソッドを個別にテストするためにテストを作成する必要はありません。プライベートメソッドと静的メソッドをテストするには、パブリックメソッドを呼び出し、次にプライベートメソッドと静的メソッドを順に呼び出します。

だからあなたのコードは次のようだとしましょう:

public object GetData()
{
 object obj1 = GetDataFromWherever();
 object obj2 = TransformData(obj1);
 return obj2;
} 
private static object TransformData(object obj)
{
//Do whatever
}

TransformDataメソッドに対するテストを作成する必要はありません(できません)。代わりに、TransformDataで行われた作業をテストするGetDataメソッドのテストを記述します。

5
Carlton Jenke

可能な場合はインスタンスメソッドを使用します。

インスタンスメソッドが不可能な場合は、public static Func [T、U](モック関数の代わりに使用できる静的関数参照)を使用します。

4
Amy B

簡単な解決策は、静的クラスの実装をセッター経由で変更できるようにすることです。

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を呼び出します。利点は、静的クラスのクライアントを変更する必要がないことです。欠点は、静的クラスのメソッドとその実装を繰り返す必要があるため、コードが少し重複する可能性があることです。しかし、静的メソッドは、基本的な機能を提供するより柔軟なインターフェースを使用できる場合があります。

0
asterite

あなたが持っている問題は、サードパーティのコードを使用していて、それがメソッドの1つから呼び出されたときです。最終的に行ったのは、オブジェクトにラップし、それをdep injで渡して呼び出すことです。これにより、単体テストでサードパーティの静的メソッドをモックして、セッターを呼び出すことができます。

0
dstarh