2017-06-09 35 views
1

MockitoとJUnitを使用してマルチスレッドアプリケーションをテストしようとしています。ここで問題のコードの一部です:Mockito ArgumentCaptorが多数の繰り返しレコードを取得しています

ArgumentCaptor<MessageCreator> messageCaptor = ArgumentCaptor.forClass(MessageCreator.class); 

jmsHandler.put(message); 

Mockito.verify(mockJmsTemplate, Mockito.after(10000).times(4)).send(messageCaptor.capture()); 

jmsHandler.put(message)ラインはBlockingQueueになり、マルチスレッドの部分で始まるアプリケーションへStringを置きます。次に、メソッドが次の10秒間に4回実行され、結果が取得されるのを待ちます。

アプリケーションはMessageCreatorの4つのインスタンスを吐き出す必要があります。これは私の目的では、予期した出力と比較するStringを含むオブジェクトに過ぎません。テスト中のログにより、4つのメッセージが作成されていることが確認されます。私は、結果を確認するためにArgumentCaptorgetAllValues()方法をループしてみました

は、しかし、私はListは文字通り数百万回を私のプログラムの出力を複製していることに気づきました。それには4つのオブジェクトが必要ですが、最後の実行には6,984,988があります。

この数値は多少の変動はあるようですが、デバッグモードでテストタイミングを巡って大きく変化します。たとえば、jmsHandler行にブレークポイントを設定し、ステップを進めて、Mockito.verify(...)ステップを開始する前にアプリケーションが処理を完了するのを待つと、Listのサイズは "単なる" 158,636オブジェクトに激減します。

誰かがこの種の問題に遭遇したことはありますか?これ以上の詳細をご提供できない場合は、私にお知らせください。

編集:ここでは、テストとプログラム構造の自己完結型の例です:

import static org.junit.Assert.assertEquals; 

import java.util.ArrayList; 
import java.util.List; 
import java.util.concurrent.ArrayBlockingQueue; 
import java.util.concurrent.BlockingQueue; 

import javax.jms.JMSException; 
import javax.jms.Message; 
import javax.jms.Session; 
import javax.jms.TextMessage; 

import org.junit.Before; 
import org.junit.Test; 
import org.mockito.ArgumentCaptor; 
import org.mockito.Mock; 
import org.mockito.Mockito; 
import org.mockito.MockitoAnnotations; 
import org.springframework.jms.core.JmsTemplate; 
import org.springframework.jms.core.MessageCreator; 

public class MultiThreadTest { 
    private Input inputHandler; 
    @Mock 
    private JmsTemplate mockJmsTemplate; 

    @Before 
    public void setup() { 
     MockitoAnnotations.initMocks(this); 

     BlockingQueue<String> queue = new ArrayBlockingQueue<String>(10); 

     inputHandler = new Input(); 
     inputHandler.setQueue(queue); 

     Output outputHandler = new Output(); 
     outputHandler.setQueue(queue); 
     outputHandler.setJmsTemplate(mockJmsTemplate); 
     new Thread(outputHandler).start(); 
    } 

    @Test 
    public void testMessage() { 
     ArgumentCaptor<OutputMessageCreator> messageCaptor = ArgumentCaptor.forClass(OutputMessageCreator.class); 

     String inMessage = "testMessage"; 

     List<String> expectedMessages = new ArrayList<String>(4); 

     inputHandler.put(inMessage); 

     Mockito.verify(mockJmsTemplate, Mockito.after(10000).times(4)).send(messageCaptor.capture()); 
     System.out.println("Number: " + messageCaptor.getAllValues().size()); 
     System.out.println("Equal: " + messageCaptor.getAllValues().get(0).equals(messageCaptor.getAllValues().get(0))); 
     System.out.println("Equal: " + messageCaptor.getAllValues().get(0).equals(messageCaptor.getAllValues().get(1))); 
     System.out.println("Equal: " + messageCaptor.getAllValues().get(0).equals(messageCaptor.getAllValues().get(2))); 
     System.out.println("Equal: " + messageCaptor.getAllValues().get(0).equals(messageCaptor.getAllValues().get(3))); 
     System.out.println("Equal: " + messageCaptor.getAllValues().get(0).equals(messageCaptor.getAllValues().get(4))); 
     System.out.println("Equal: " + messageCaptor.getAllValues().get(0).equals(messageCaptor.getAllValues().get(5))); 
     System.out.println("Equal: " + messageCaptor.getAllValues().get(0).equals(messageCaptor.getAllValues().get(6))); 
     System.out.println("Equal: " + messageCaptor.getAllValues().get(0).equals(messageCaptor.getAllValues().get(7))); 
     System.out.println("Equal: " + messageCaptor.getAllValues().get(0).equals(messageCaptor.getAllValues().get(8))); 

     List<String> outMsgs = new ArrayList<String>(); 
     for (OutputMessageCreator creator : messageCaptor.getAllValues()) { 
      outMsgs.add(creator.getMsg()); 
     } 
     assertEquals(expectedMessages, outMsgs); 
    } 

    private class Input { 
     private BlockingQueue<String> queue; 

     public void put(String msg) { 
      try { 
       queue.put(msg); 
      } catch (InterruptedException e) { 
       e.printStackTrace(); 
      } 
     } 

     public void setQueue(BlockingQueue<String> queue) { 
      this.queue = queue; 
     } 
    } 

    private class Output implements Runnable { 
     private BlockingQueue<String> queue; 
     private JmsTemplate jmsTemplate; 
     private int counter = 1; 

     @Override 
     public void run() { 
      while (true) { 
       String msg = null; 
       try { 
        msg = queue.take(); 
        String[] messagesOut = new String[4]; 
        for (int i = 0; i < 4; i++) { 
         messagesOut[i] = msg + "-" + counter++; 
        } 

        for (String messageOut : messagesOut) { 
         System.out.println(messageOut); 
         jmsTemplate.send(new OutputMessageCreator(messageOut)); 
         Thread.sleep(2000); 
        } 
       } catch (InterruptedException e) { 
        e.printStackTrace(); 
       } 
      } 
     } 

     public void setQueue(BlockingQueue<String> queue) { 
      this.queue = queue; 
     } 

     public void setJmsTemplate(JmsTemplate jmsTemplate) { 
      this.jmsTemplate = jmsTemplate; 
     } 
    } 

    private class OutputMessageCreator implements MessageCreator { 
     private String msg; 

     public OutputMessageCreator(String msg) { 
      this.msg = msg; 
     } 

     @Override 
     public Message createMessage(Session session) throws JMSException { 
      TextMessage message = session.createTextMessage(); 
      message.setText(msg); 
      return message; 
     } 

     public String getMsg() { 
      return msg; 
     } 
    } 
} 

は、ここでそのテストを実行しているからの出力です:

testMessage-1 
testMessage-2 
testMessage-3 
testMessage-4 
Number: 5392168 
Equal: true 
Equal: false 
Equal: false 
Equal: false 
Equal: true 
Equal: false 
Equal: false 
Equal: false 
Equal: true 
+1

問題はArgumentCaptorなしで発生しますか?はいの場合は、タイトルを変更することができます。いずれにしても、実際の例を提示することができます。 – jdebon

+0

@jdebonフィードバックいただきありがとうございます。問題は 'ArgumentCaptor'です。テスト自体は期待通りに4つのメッセージしか作成しませんが、 'ArgumentCaptor'は何百万回も繰り返しキャプチャしています。つまり、 'getAllValues()'は[msg1、msg2、msg3、msg4、msg1、msg2、msg3、msg4、msg1、...]を返します。私は元の質問に問題のレクリエーションを付けました。 – ryoung10

答えて

0

これはMockitoのバグだったように見えますいくつかの点で:

https://github.com/mockito/mockito/issues/345

https://github.com/mockito/mockito/issues/379

問題は、これがMockito 2または2.1で修正されたことを暗示していますが、私は2.0.41-betaを使用していて、2.4.0と2.8.9を試して同じ結果を得ました。 github問題のコメントの中には、ある種の問題があるようです。

このコード行:私は修正が実際にリリースされたかどうかを確認するために、問題379についてコメントしましたが、それはのように思える

try { 
    Thread.sleep(10000); 
} catch (InterruptedException e) { 
    e.printStackTrace(); 
} 

Mockito.verify(mockJmsTemplate, Mockito.times(4)).send(messageCaptor.capture()); 

Mockito.verify(mockJmsTemplate, Mockito.after(10000).times(4)).send(messageCaptor.capture()); 

はこれで置き換えることができますこの作業は今のところトリックを行います。

関連する問題