web-dev-qa-db-ja.com

静的voidメソッドがpower mockitoで呼び出されたことを確認する方法

私は以下を使用しています。

Powermock-mockito 1.5.12
Mockito 1.95
junit 4.11

これが私のutilsクラスです

public void InternalUtils {
    public static void sendEmail(String from, String[] to, String msg, String body) {
    }
}

テスト対象のクラスの要点は次のとおりです。

public class InternalService {
       public void processOrder(Order order) {
           if (order.isSuccessful()) {
               InternalUtils.sendEmail(...);
           }
       }
}

そして、ここにテストがあります:

@PrepareForTest({InternalUtils.class})
@RunWith(PowerMockRunner.class)
public class InternalService {
   public void verifyEmailSend() {
        mockStatic(Internalutils.class);
        doNothing().when(InternalUtils, "sendEmail", anyString(), any(String.class), anyString(), anyString());
        Order order = mock(Order.class);
        when(order.isSuccessful()).thenReturn(true);
        InternalService is = new InternalService();

        verifyStatic(times(1));
        is.processOrder(order);
   }
}

上記のテストは失敗します。指定された検証モードはありませんが、コードによると、注文が成功した場合、電子メールを送信する必要があります。

41
Chun ping Wang

doNothing()のようなもので)動作をモックしている場合、verify*()を呼び出す必要はありません。そうは言っても、テストメソッドを書き直す際の私の刺し傷です。

@PrepareForTest({InternalUtils.class})
@RunWith(PowerMockRunner.class)
public class InternalServiceTest { //Note the renaming of the test class.
   public void testProcessOrder() {
        //Variables
        InternalService is = new InternalService();
        Order order = mock(Order.class);

        //Mock Behavior
        when(order.isSuccessful()).thenReturn(true);
        mockStatic(Internalutils.class);
        doNothing().when(InternalUtils.class); //This is the preferred way
                                               //to mock static void methods.
        InternalUtils.sendEmail(anyString(), anyString(), anyString(), anyString());

        //Execute
        is.processOrder(order);            

        //Verify
        verifyStatic(InternalUtils.class); //Similar to how you mock static methods
                                           //this is how you verify them.
        InternalUtils.sendEmail(anyString(), anyString(), anyString(), anyString());
   }
}

何が起こっているかをより強調するために、4つのセクションにグループ分けしました。

1.変数

ここでは、インスタンス変数/メソッド引数/モックコラボレーターを宣言することを選択します。複数のテストで使用されるものである場合は、テストクラスのインスタンス変数にすることを検討してください。

2.モック動作

ここで、すべてのモックの動作を定義します。テスト対象のコードを実行する前に、ここで戻り値と期待値を設定しています。一般的に、ここでモックの動作を設定した場合、後で動作を確認する必要はありません。

3.実行する

ここで空想はありません。これにより、テスト対象のコードが開始されます。私はそれに注意を喚起するためにそれ自身のセクションを与えるのが好きです。

4.確認

これは、verifyまたはassertで始まるメソッドを呼び出すときです。テストが終わったら、あなたがしたかったことが実際に起こったことを確認します。それはあなたのテスト方法で見た最大の間違いです。実行の機会が与えられる前にメソッド呼び出しを検証しようとしました。 2番目に、検証したい静的メソッドwhichを指定しなかったことです。

その他の注意事項

これは主に個人的な好みです。あなたが物事を行うために必要な特定の順序がありますが、各グループ内には小さな動きの余地があります。これにより、どこで何が起こっているのかをすばやく区別できます。

また、次のサイトの例を確認することを強くお勧めします。これらの例は非常に堅牢であり、必要なケースの大部分を支援できるためです。

53
Matt Lachman

上記の答えは広く受け入れられ、十分に文書化されています。ここに私の答えを投稿する理由のいくつかを見つけました:-

    doNothing().when(InternalUtils.class); //This is the preferred way
                                           //to mock static void methods.
    InternalUtils.sendEmail(anyString(), anyString(), anyString(), anyString());

ここで、InternalUtils.sendEmailを自分で呼び出す理由を理解できません。私たちがそれをする必要がない理由をコードで説明します。

mockStatic(Internalutils.class);

だから、私たちは素晴らしいクラスをモックしました。次に、sendEmail(/..../)メソッドを検証する方法を見てみましょう。

@PrepareForTest({InternalService.InternalUtils.class})
@RunWith(PowerMockRunner.class)
public class InternalServiceTest {

    @Mock
    private InternalService.Order order;

    private InternalService internalService;

    @Before
    public void setup() {
        MockitoAnnotations.initMocks(this);
        internalService = new InternalService();
    }

    @Test
    public void processOrder() throws Exception {

        Mockito.when(order.isSuccessful()).thenReturn(true);
        PowerMockito.mockStatic(InternalService.InternalUtils.class);

        internalService.processOrder(order);

        PowerMockito.verifyStatic(times(1));
        InternalService.InternalUtils.sendEmail(anyString(), any(String[].class), anyString(), anyString());
    }

}

これらの2行は魔法のあるところです。最初の行はPowerMockitoフレームワークに、静的にモックされたクラスを検証する必要があることを伝えます。しかし、どのメソッドを検証する必要がありますか?? 2行目は、検証する必要があるメソッドを示します。

PowerMockito.verifyStatic(times(1));
InternalService.InternalUtils.sendEmail(anyString(), any(String[].class), anyString(), anyString());

これは、私のクラスのコード、sendEmail apiを2回使用しています。

public class InternalService {

    public void processOrder(Order order) {
        if (order.isSuccessful()) {
            InternalUtils.sendEmail("", new String[1], "", "");
            InternalUtils.sendEmail("", new String[1], "", "");
        }
    }

    public static class InternalUtils{

        public static void sendEmail(String from, String[]  to, String msg, String body){

        }

    }

    public class Order{

        public boolean isSuccessful(){
            return true;
        }

    }

}

2回呼び出しているので、verify(times(2))...を変更するだけです。

16
Arpit