2012-03-31 57 views
7

スーパークラスSをモックするためにMockitoと任意選択でPowermockを使用することが可能です(S()コンストラクタへの呼び出しを含む)Sへのスーパークラスへの呼び出しはすべて非難されますか?したがって、以下の例を使用して、をMockitoを使用してMockSに置き換えた場合、super()への呼び出しはMockSのコンストラクタを使用しますか?私はSで個々のメソッドをからかったりだけあざけるについての質問を見てきましたスーパークラスのコンストラクタをMockito/Powermockでモックすることはできますか?

class S { 
    S() { 
     // Format user's hard drive, call 911, and initiate self-destruct 
    } 
} 

class T extends S { 
    T() { 
     super(); 
    } 
} 

class Test { 
    @Mock private S mockS; 
    new T(); // T's call to super() should call the mock, not the destructive S. 
} 

super()に呼び出し、これはサポートされていないことを読んで、それは私が全体のスーパークラスを模擬できるかどうかは明らかではありません。

私の現在のテストでは、Sを模擬しようとすると、super()へのTの呼び出しは模擬ではなく実際の実装を呼び出します。

+0

どのようにあなたのモックコールスーパー()?あなたはコード例を提供できますか? – nansen

+0

@nansen私はモックから 'super()'を呼び出すのではなく、モックはスーパークラスです。私の編集内容を見てください。 –

+1

私はそのクラス 'S'が大好きです。 – DerMike

答えて

4

この明白な制限を回避するために、私は自分のコードreplacing inheritance with delegationをリファクタリングしました。継承が本当に必要なわけではないので、とにかくより良いデザインで終わったと思います。

新しいコードは次のようになります。質問のコードが簡素化されているので、実際のクラスにはもっと多くの機能があります。 GuiceのとAndroidを使用して興味のある方のため

class S { 
    S() { 
     // Format user's hard drive, call 911, and initiate self-destruct 
    } 
} 

class T { 
    T(S s) {} // Now T "has an S" instead of "is an S" 
} 

class Test { 
    @Mock private S mockS; 
    new T(s); // T's call to super() should call the mock, not the destructive S. 
} 

は、テストはより次のようになります。

class T { 
    T(Activity activity, S s) {} 
} 

class Test { 
    @Mock Activity activity; 
    @Mock S mockS; 
    injector = Guice.createInjector(new AbstractModule() { 
    @Override protected void configure() { 
     bind(Activity.class).toInstance(activity); 
     bind(S.class).toInstance(mockS); 
    }} 
); 
    T t = injector.getInstance(T.class); 
} 
+0

こんにちは、私はここに記述されているものに似た何かを達成しようとしていますが、これをテストしていますが、BindEverythingElse()のコンパイルエラーを示しています。依存。他の依存関係を追加する必要がありますか、何か不足していますか?ありがとう!! – Rishi

+0

@Rishi他のカスタムバインディングがない場合は、その行を削除してください。実際、答えには無関係なので、私はそれを取り除いています。 –

3

これは、子のメソッドがスーパークラスのメソッドと異なる場合(つまり、子がそのメソッドをオーバーライドする場合、親メソッドをモックすることはできません)、PowerMockでは可能です。もう少し詳しくは、the relevant bug reportをご覧ください。

PowerMockの場合は、Suppressing Unwanted Behavior pageを調べて、必要に応じて十分かどうかを確認してください。


はあまり周りに掘った後、私はこれらのトリッキーな例についてJMockitを使用して終了しました。私がJMockitに移る前に、抑制を使用して例外がスローされたすべての場所をスタブしてみました。結局、私はいくつかのメソッドをオーバーライドする必要があっただけでなく、それらを抑制するため、私はそれを放棄して終了しました。 Androidの場合の

使用例:アクティブにすると

@MockClass(realClass = Activity.class, instantiation = PerMockedInstance) 
public class FakeActivity { 
    public Bundle mSavedInstanceState; 

    @Mock 
    public void $init() {} 

    @Mock 
    public void onCreate(Bundle savedInstanceState) { 
     mSavedInstanceState = savedInstanceState; 
    } 
} 

、このクラスは$init()Activityのデフォルトコンストラクタを交換し、交換します:

まず、あなたは@MockClass注釈を使用して、スーパークラスをモック上記のものとonCreateメソッド。アンドロイドでは、テスト対象のユニットはアクティビティから派生しています(私のサンプルコードではHelloTestActivity)。テストクラスは次のようになります。

public class HelloTestActivityTest3 extends AndroidTest { 
    @Tested 
    HelloTestActivity activity; 

    FakeActivity fakeActivity = new FakeActivity(); 

    @Before 
    public void setupMocks() 
    { 
     Mockit.setUpMock(fakeActivity); 
    } 

    @Test 
    public void onCreate_bundle(@Mocked Bundle savedInstanceState) 
    { 
     // Try to access out-of-band information from the fake 
     activity.onCreate(savedInstanceState); 
     assertSame(savedInstanceState, fakeActivity.mSavedInstanceState); 
    } 
} 

コールMockit.setupMock(fakeActivity)偽の私のインスタンスでスーパークラスを置き換えます。この使用法では、偽のクラスの内部状態にもアクセスできます。カスタム機能を持つメソッドをオーバーライドする必要がない場合は、Mockitクラスから利用できる他のメソッドを使用できます。

rogerioが以下のコメントで指摘したように、Activityクラスを嘲笑することは最低限です。次のコードはこれを示しています。

public class HelloTestActivityTest4 { 
    @Tested 
    HelloTestActivity activity; 

    @Mocked 
    Activity base; 

    @Test 
    public void testOnCreate() throws Exception { 
     // Just make sure "Stub!" exception is not thrown. 
     activity.onCreate(null); 
    } 
} 

Activityクラスの全てのメソッド(静的初期を除く)を引き起こし、そのスーパークラスがHelloActivityTest4で定義されたテストでモックする@Mocked Activity base;宣言。

+0

これは私の誤解かもしれませんが、私はスーパークラス全体を嘲笑することについて話しています。私の編集を見て、私に知らせてください。 –

+0

私はJMockitを使って、それぞれのメソッドが "Stub!"例外をスローする "偽の" android Activityクラスを模倣しました。 JVMから呼び出されたときスーパーをモックするか、または特定のメソッドをショートカットを実行し、残りの部分をモックしたり、コンストラクタや静的イニシャライザブロックなどを削除するフェイクに置き換えることができます。PowerMockでは柔軟性が利用できません。しかし、私は変更を読んで、必要に応じて私の答えを修正します。 – vhallac

+0

私たちはすべてAndroidのためにPowermockを使用していますか? :)私は既に 'Activity'を嘲笑しました(Roboguiceでそれらを注入し、' Activity.class'をインスタンス 'mockActivity'にバインドします)。このSOの投稿の場合、私は 'ArrayAdapter'への拡張をテストし、それを' S'に一般化しました。成功するために、継承を代理人に置き換え、注入された代理人を嘲笑しました。 –

1

スーパークラスのコンストラクタの '危険な'コードを非公開のメソッドに抽出し、クラスTでMockitoスパイを使用し、抽出されたメソッドの動作をオーバーライドすることができます。

これはもちろん、カプセル化に違反します。 Guavaでは、このような場合の注釈はVisibleForTestingです。

+0

PowerMockitoを使用すると、PowerMockito.whenNew(S.class).withNoArguments()。thenReturn(mockedS);が返されます。これは、明示的に新しいS()を呼び出すが、super()では呼び出さないときに機能します。書式設定された私のハードドライブ;) – nansen

+1

私は委任で継承を置き換え、その後、代議員を嘲笑してしまいました。 –

+0

これははるかに良いです。 +1 – nansen

関連する問題