web-dev-qa-db-ja.com

@RunWith(PowerMockRunner.class)vs @RunWith(MockitoJUnitRunner.class)

_@Mock_および_@InjectMocks_注釈を使用した通常のモックでは、テスト中のクラスは@RunWith(MockitoJUnitRunner.class)を使用して実行する必要があります。

_@RunWith(MockitoJUnitRunner.class)
public class ReportServiceImplTestMockito {

     @Mock 
     private TaskService      mockTaskService;

     @InjectMocks 
     private ReportServiceImpl service;

         // Some tests
}
_

しかし、いくつかの例では、@RunWith(PowerMockRunner.class)が使用されています:

_@RunWith(PowerMockRunner.class)
public class Tests {
  @Mock
  private ISomething mockedSomething;

  @Test
  public void test1() {
    // Is the value of mockedSomething here
  }

  @Test
  public void test2() {
    // Is a new value of mockedSomething here
  }
}
_

誰かが違いを指摘し、別のものの代わりに1つを使用したいときに指摘できますか?

17
Johan

一見したところ、答えは単純です。まあ、いくつかのモックフレームワークがあり、それらを使用するさまざまな方法があります。

最初の例は、Mockitoモックフレームワークが提供する「ユニットテストランナー」を使用するようJUnitに指示します。 2番目の例では、PowerMockフレームワークの単体テストランナーを使用しています。

意味を理解するために、たとえば、両方のフレームワークに@Mockアノテーションのdifferent実装があるため、異なるimportステートメントもあります。

(これらのフレームワーク固有のテストランナーを使用する主なポイントは、特別なフレームワーク固有の注釈ですべてのフィールドを初期化することです)。

そのため、ここでの違いは単純です。最初の例はMockitoフレームワークを使用するように記述されており、2番目の例はPowerMockを使用している。

さて、使用するのはどれですか?

回答:Mockito。

どうして?どういうわけかい真実は次のとおりです。PowerMock-oneは基本的に助けを求める声です。 「テスト対象のクラスの設計が不適切です。修正してください」と表示されます。意味:開発者は、「テストしやすい」コードまたは「テストしにくい」コードを作成できます。多くの人が2つ目を行います。テストするのが難しいコードを書いています。そして、PowerMock(ito)はそのコードをstillテストする手段を提供します。

PowerMock(ito)を使用すると、staticメソッドおよびnew()への呼び出しをモック(制御)できます。これを有効にするために、PowerMock(ito)はテスト中のコードのバイトコードを操作します。これは小さなコードベースではまったく問題ありませんが、数百万行の製品コードと数千の単体テストに直面すると、状況はまったく異なります。

明らかな理由もなく多くのPowerMockテストが失敗し、数時間後に発見されました。他の場所で「静的」なものが変更され、別のPowerMock静的/新しい駆動テストケースに何らかの影響を及ぼします。

ある時点で、私たちのチームは意識的な決定を下しました。新しいコードを書くとき、PowerMockでしかテストできません...それは受け入れられません。それ以来、Mockitoのテストケースのみを作成し、PowerMockで私たちを悩ませた同様の奇妙な問題を一度は作成しませんでした。

PowerMockを使用する唯一の受け入れられる理由は、変更したくない既存の(おそらくサードパーティの)コードをテストする場合です。しかし、もちろん、そのようなコードをテストするポイントは何ですか?そのコードを変更できない場合、テストが突然失敗するのはなぜですか?

22
GhostCat

PowerMockが最初の選択肢になることはありません。 PowerMockでのみテスト可能なクラスを作成したばかりの場合、何か間違ったことをしました。クラスには依存関係の注入または依存関係のあるコンストラクターが必要です。そのため、テストは容易になります。もちろん、静的メソッドは通常のフレームワークではモックできないため、使用しないでください(read:mockito)。

一方、大きなプロジェクトがあり、前の開発者がそれをしなかったためにユニットテストを追加する場合、PowerMockはすべてを完全にリファクタリングせずに唯一のソリューションになります。そして、その観点ではテストなしのPowerMockを好む

PowerMockはバイトコードを変更し、JaCoCo(SonarQubeカバレッジランナー)のコードカバレッジは機能しませんが、IntelliJコードカバレッジランナーはPowerMockで機能するため、汚れています。

1つのクラスで1つのメソッドをMockitoでテストできない場合、テストを分割します。1つのテストクラスはMockitoで、もう1つのテストクラスはPowerMockです。これにより、SonarQubeのコードカバレッジが向上します。

public class ClassToTest {

    public void testableMethod() {
        /* Do something */
    }

    public String methodWithStaticCall() {
        return MyTest.staticMethod();
    }
}

次に、最初のメソッドをテストする1つのクラスがあります。

@RunWith(MockitoJUnitRunner.class)
public class testClassToTest() {
   private sut = new ClassToTest();

   @Test
   public testMethod() {
       sut.testableMethod();
   }
}

そして、PowerMockの1つ:

@RunWith(PowerMockJUnitRunner.class)
@PrepareForTest({MyTest.class, ClassToTest.class})
public class testClassToTestPM() {
   private sut = new ClassToTest();

   @Before
   public void before() {
       mockStatic(MyTest.class);
   }

   @Test
   public testMethod() {
       mockStatic(MyTest.class);
       when(MyTest.staticMethod()).thenReturn("test");
       assertEquals("test", sut.methodWithStaticCall());
   }
}
1
Sven

PowerMock を使用すると、静的メソッドとプライベートメソッド、および最終クラスなどをモックできます。

PowerMockは、EasyMockなどの他のモックライブラリをより強力な機能で拡張するフレームワークです。 PowerMockは、カスタムクラスローダーとバイトコード操作を使用して、静的メソッド、コンストラクター、最終クラスとメソッド、プライベートメソッド、静的初期化子の削除などのモックを有効にします。

code smellがあります。これらのタイプのコンポーネントをモックする必要がある場合は、but役に立つかもしれません。ある時点で静的ヘルパークラスを作成し、モックする必要のある依存関係を作成した古いプロジェクトで作業している可能性があります。アーキテクチャを変更できる場合は、デザインを修正!それ以外の場合、テストに適切なテクノロジを使用します。

静的またはプライベート関数をモックする必要がない場合は、PowerMockを使用する必要はありません。 PowerMockは、他のモックフレームワークのラッパーです。

0
Phil Ninan