2016-05-31 13 views
0

Ich muss den Unit Test von unten Code, der countdownlatch verwendet. Dies ist nur ein Testcode. Ich benutze Mockito dannAnswer und InvocationOnMask für spöttische Threads/aufrufbar. Aber ich weiß nicht, wie man countdownlatch beim Komponententesten initialisiert/verspottet oder beendet.How to Unit Testen Sie eine Methode mit CountDownLatch?

public class ThreadPoolTaskExecRunner { 
    private ThreadPoolTaskExecutor threadPoolTaskExecutor = new ThreadPoolTaskExecutor(); 
    private ArrayBlockingQueue<String> values = new ArrayBlockingQueue<String>(100, true); 

    public ThreadPoolTaskExecRunner() { 
     threadPoolTaskExecutor.setCorePoolSize(5); 
     threadPoolTaskExecutor.setMaxPoolSize(10); 
     threadPoolTaskExecutor.setWaitForTasksToCompleteOnShutdown(true); 
     threadPoolTaskExecutor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy()); 
     threadPoolTaskExecutor.initialize(); 
    } 

    public static void main(String args[]) { 
     ThreadPoolTaskExecRunner obj = new ThreadPoolTaskExecRunner(); 
     obj.testCountDownLatch(); 
    } 
    public void testCountDownLatch() { 
     final CountDownLatch latch = new CountDownLatch(5); 
     Future<String> future1 = threadPoolTaskExecutor.submit(new Task("A", values, latch)); 
     Future<String> future3 = threadPoolTaskExecutor.submit(new Task("B", values, latch)); 
     Future<String> future4 = threadPoolTaskExecutor.submit(new Task("C", values, latch)); 
     Future<String> future5 = threadPoolTaskExecutor.submit(new Task("D", values, latch)); 
     Future<String> future2 = threadPoolTaskExecutor.submit(new Task("E", values, latch)); 

     try{ 
      latch.await(); //main thread is waiting on CountDownLatch to finish 
     }catch(InterruptedException ie){ 
      System.out.println(ie); 
     } 
     System.out.println("*********** DONE *********** values size= "+values.size()); 
     for(String s : values) 
      System.out.println(s); 
     threadPoolTaskExecutor.shutdown(); 
    } 

    public static class Task implements Callable<String> { 
     private String type; 
     private ArrayBlockingQueue<String> values; 
     private CountDownLatch latch; 

     public Task(String s, ArrayBlockingQueue<String> values, CountDownLatch latch) { 
      this.type = s; 
      this.values = values; 
      this.latch = latch; 
     } 

     @Override 
     public String call() throws Exception { 
      try { 
       System.out.println("Inside call type: " + type); 
       Thread.sleep(10); 
       values.add(type); 
       return type; 
      } finally { 
       if(latch != null) 
        latch.countDown(); 
      } 
     } 
    } 
} 

ich die Unit-Test-Klasse entwickelt, aber es ist nicht hilfreich ...

@RunWith(MockitoJUnitRunner.class) 
public class ThreadPoolTaskExecRunnerTest { 
    @Mock 
    private ThreadPoolTaskExecutor taskExecutor; 

    @InjectMocks 
    ThreadPoolTaskExecRunner threadPoolTaskExecRunner; 

    @Test 
    public void test() { 
     when(taskExecutor.submit(any(ThreadPoolTaskExecRunner.Task.class))).thenAnswer(new Answer<Future<String>>() { 
      public Future<String> answer(InvocationOnMock invocation) throws Throwable { 
       Future<String> future = mock(FutureTask.class); 
       when(future.isDone()).thenReturn(false, false, true); 
       when(future.get()).thenReturn("This is a test"); 
       return future; 
      } 
     }); 

     threadPoolTaskExecRunner.testCountDownLatch(); 
    } 
} 
+0

Sie sollten Code nicht testen, den Sie nicht geschrieben haben ... Haben Sie jemals einen Komponententest auf List/Array/Integer und etc geschrieben? Was genau wollen Sie testen? – alfasin

+0

Sieht aus wie mein Methodenname testCountDownLatch() Sie verwirrt. Mein Dienst muss einige Aufgaben parallel ausführen, und es sollte warten, bis alle Aufgaben abgeschlossen sind. Ich benutze countdowlatch dafür. Jetzt muss ich meinen Service testen. Bitte behandeln Sie die Methode testCountDownLatch() als meine Service-Methode ... – ganesh

Antwort

1

Nun, was wollen Sie testen? Ich nehme an, dass Sie testen möchten, dass countDown aufgerufen wurde. So können Sie es wie folgt tun:

public void taskCallsCountDownOnce() { 
    // setup 
    final CountDownLatch latch = mock(CountDownLatch.class); 

    // execution 
    new Task("A", values, latch).call(); 

    // evaluation 
    verify(latch).countDown(); 
} 

Wenn auch Sie testen wollen, dass der Wert vor dem Aufruf von Count-down hinzugefügt wurde, dann verwenden:

public void taskAddsValueBeforeCallingCountDown() { 
    // setup & execution 
    // ... 
    // evaluation 
    InOrder inOrder = inOrder(latch, values); 
    inOrder.verify(values).add(...); 
    inOrder.verify(latch).countDown(); 
} 

Allgemeine Hinweise:

  • In In diesem speziellen Fall wäre es einfacher zu rufen Future.get(), die auch warten, bis die Aufgabe abgeschlossen
  • Geben Sie Ihre Testmethoden beschreibende Namen, die helfen Verstehen Sie, was Sie testen
  • Versuchen Sie, die Parallelität so weit wie möglich von Ihrem Komponententest entfernt zu halten. Die meisten Klassen beschäftigen sich nicht mit Nebenläufigkeit selbst wie Ihre Klasse Task. Es ist egal, ob es in einem neuen Thread ausgeführt wird, es passiert einfach in deinem Fall. Sie können diese Klasse also separat testen. Wenn Sie Ihren Code gut strukturieren, werden Sie Klassen haben, die sich mit Thread-Organisation und nichts anderem beschäftigen, und andere Klassen, die Arbeit und nichts anderes erledigen. Dadurch wird der Test für Algorithmen und der Test für die Thread-Handhabung einfacher und die Tests einfacher zu lesen.