2016-05-16 24 views
2

私のテストケースの作成にはJunit4Mockitoを使用しています。テスト中のクラスの1つに、コンストラクタから呼び出される関数init()があります。android.os.Handlerクラスのスタブポストメソッドはありません

void init(){ 
//Some code 
    Handler handler = new Handler(Looper.getMainLooper()); 
    handler.post(new Runnable() { 
     @Override 
     public void run() { 
     //Some code 
     } 
    }); 
} 

このクラスのconstructorを作成しようとすると、次の例外がスローされます。

java.lang.RuntimeException: Method post in android.os.Handler not mocked. 

は、それから私は、次のコード

Handler handler = spy(new Handler()); 
when(handler.post(Matchers.any(Runnable.class))).thenReturn(true); 

を使用してHandlerクラスのpost方法を模擬することを試みた。しかし、まだ私は同じexceptionを取得し続けます。 Handlerクラスのpostメソッドをスタブするにはどうすればよいですか?

答えて

0

あなたの文脈をもっと見ることなく言うのは難しいですが、2つの選択肢があります。

まず、能力があれば、模擬する必要のあるものに対してnewを使用することを避けることができます。コンストラクタに注入するか、コンストラクタにファクトリを挿入してファクトリをモックして、モックHandlerを取得します。ほとんどの場合、これらの行に沿ったものが好ましいアプローチです。

実用的でない場合は、PowerMock to construct new objectsを使用できます。

PowerMockito.whenNewを使用してください。

Handler handler = spy(new Handler()); 
when(handler.post(Matchers.any(Runnable.class))).thenReturn(true); 
whenNew(Handler.class).withExpectedArguments(looper).thenReturn(handler); 

このコードはテストされていませんが、基本的に動作するはずです。

0

あなたは「メソッド嘲笑ない」の解釈で正しいです:あなたはa no-implementation version of the Android system libraryを使用しているので、あなたがここに嘲笑使用する必要がある、またはあなたがテストのためHandlerのようなクラスのJava実装を持っているRobolectricのようなライブラリに切り替える必要がありますが。

あなたのスタブにはdoReturnが必要です。when構文の興味深い意図しない側面の一つは、それが実際にはスタブのメソッドを呼び出すことです:

when(handler.post(Matchers.any(Runnable.class))).thenReturn(true); 
// calls 
// handler.post(   null   ) 

そして、スパイは、デフォルトでは、実際のメソッドを呼び出すので、あなたが実際にスタブしようとしているときに問題のあるメソッドを呼び出しますそれ。代わりに、doReturnを使用して、Mockitoにスタブを一時的に無効にするよう指示します。

doReturn(true).when(handler).post(Matchers.any(Runnable.class)); 

テストにスタブを挿入する必要があります。これは、コンストラクターで「重い持ち上げ」を行っているため、ややこしいことです。あなたはあなたのハンドラを交換するために建設後の機会に失います。 jhericks mentions a PowerMock solution、あなたが建設にあまりをしない、第三の選択肢として使用すると、テストの過負荷でこれを回避することができるように私はリファクタリングをお勧めしますけれども:

public class YourClass { 
    /** Public constructor for external access. */ 
    public YourClass() { 
    this(new Handler(Looper.getMainLooper())); 
    } 

    /** Package-private constructor for testing. */ 
    YourClass(Handler handler) { 
    init(handler); 
    } 

    private void init(Handler handler) { 
    handler.post(new Runnable() { 
     @Override public void run() { 
     //Some code 
     } 
    }); 
    } 
} 

サイドノート:initがプライベートであることを余分に注意してくださいまたは最終的には、it's dangerous to call overridable methods from constructorsです。

関連する問題