web-dev-qa-db-ja.com

mockitoを使用したコンストラクターの単体テスト

クラスが1つあります。

Class First {

    private Second second;

    public First(int num, String str) {
        second = new Second(str);
        this.num = num;
    }

    ... // some other methods
}

Firstクラスのパブリックメソッドの単体テストを記述したいと思います。 Secondクラスのコンストラクターの実行を避けたい。

これは私がしました:

Second second = Mockito.mock(Second.class);
Mockito.when(new Second(any(String.class))).thenReturn(null);
First first = new First(null, null);

まだクラスSecondのコンストラクターを呼び出しています。どうすればそれを回避できますか?

33
Tarun Kumar

もう一度、単体テストの問題は、new演算子を使用してオブジェクトを手動で作成することから生じます。代わりに、既に作成されたSecondを渡すことを検討してください。

class First {

  private Second second;

  public First(int num, Second second) {
    this.second = second;
    this.num = num;
  }

  // some other methods...
}

これはAPIの大幅な書き換えを意味する可能性がありますが、他の方法はありません。また、このクラスには意味がありません。

Mockito.when(new Second(any(String.class).thenReturn(null)));

まず、Mockitoはメソッドのみをモックでき、コンストラクターはモックできません。第二に、たとえコンストラクターをモックできたとしても、作成されたばかりのオブジェクトのコンストラクターをモックしているので、そのオブジェクトを実際に使用することはありません。

25

PowerMockito を使用できます

例を参照:

Second second = Mockito.mock(Second.class);
whenNew(Second.class).withNoArguments().thenReturn(second);

しかし、リファクタリングはより良い決定です。

61
terma

以下は、PowerMockito APIを使用してこの機能をモックするコードです。

Second mockedSecond = PowerMockito.mock(Second.class);
PowerMockito.whenNew(Second.class).withNoArguments().thenReturn(mockedSecond);

Powermockitoランナーを使用する必要があり、必要なテストクラス(カンマ区切り)を追加する必要があります。これらのクラスはpowermock APIによってモックされる必要があります。

@RunWith(PowerMockRunner.class)
@PrepareForTest({First.class,Second.class})
class TestClassName{
    // your testing code
}
13
Rocky Mena

「パターン2-「ファクトリーヘルパーパターン」を使用しました

パターン2-ファクトリヘルパーパターン

このパターンが機能しない1つのケースは、MyClassが最終的な場合です。 Mockitoフレームワークのほとんどは、最終クラスでは特にうまく機能しません。これには、spy()の使用が含まれます。別のケースは、MyClassがgetClass()をどこかで使用し、結果の値をMyClassにする必要がある場合です。スパイのクラスは実際には元のクラスのMockitoが生成したサブクラスであるため、これは機能しません。

どちらの場合でも、次のように、わずかに堅牢なファクトリヘルパーパターンが必要です。

public class MyClass{
  static class FactoryHelper{
      Foo makeFoo( A a, B b, C c ){
          return new Foo( a, b, c );
      }
  }

  //...

  private FactoryHelper helper;
  public MyClass( X x, Y y ){
      this( x, y, new FactoryHelper());
  } 

  MyClass( X x, Y, y, FactoryHelper helper ){

      //...

      this.helper = helper;
  } 

  //...

  Foo foo = helper.makeFoo( a, b, c );
}

そのため、テスト用の特別なコンストラクターに追加の引数があります。これは、テストするオブジェクトを作成するときに、テストクラスから使用されます。テストクラスでは、FactoryHelperクラスと作成するオブジェクトをモックします。

@Mock private MyClass.FactoryHelper mockFactoryHelper;
@Mock private Foo mockFoo;
private MyClass toTest;

そして、あなたはこのようにそれを使用することができます

toTest = new MyClass( x, y, mockFactoryHelper ); 
when( mockFactoryHelper.makeFoo( 
  any( A.class ), any( B.class ), any( C.class )))
  .thenReturn( mockFoo ); 

ソース: http://web.archive.org/web/20160322155004/http://code.google.com/p/mockito/wiki/MockingObjectCreation

私は、mockitoを使用してコンストラクターをモックすることはできないと信じています。代わりに、次のアプローチをお勧めします

   Class First {

            private Second second;

            public First(int num, String str) {
            if(second== null){
            //when junit runs, you get the mocked object(not null), hence don't 
            //initialize            
           second = new Second(str);
           }
                this.num = num;
            }

        ... // some other methods
    }





    class TestFirst{
        @InjectMock
        First first;//inject mock the real testable class
        @Mock
        Second second
    testMethod(){

    //now you can play around with any method of the Second class using its 
    //mocked object(second),like:
    when(second.getSomething(String.class)).thenReturn(null);
        }
0