如何使用CountDownLatch对方法进行单元测试?

时间:2016-05-31 21:34:09

标签: java unit-testing countdownlatch

我需要使用countdownlatch进行以下代码的单元测试。这只是一个测试代码。我使用mockito thenAnswer和InvocationOnMask来模拟线程/可调用。但我不知道如何在单元测试中初始化/模拟或退出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();
            }
        }
    }
}

我开发了单元测试类,但它没有用......

@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();
    }
}

1 个答案:

答案 0 :(得分:2)

那你想测试什么?我想你想测试countDown被调用了。所以你可以这样做:

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

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

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

如果您还想在调用countDown之前测试该值已添加,请使用:

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

一般说明:

  • 在这种特殊情况下,调用Future.get()会更容易,这也会等到任务完成
  • 为您的测试方法提供描述性名称,以帮助您了解正在测试的内容
  • 尽可能保持并发性远离单元测试。大多数类都不像处理类Task那样处理并发问题。它不关心它是否在一个新的线程中执行,它恰好在你的情况下。所以你可以单独测试这个类。如果您很好地构建代码,那么您将拥有处理线程组织的类,而不会执行任何其他类以及执行工作的其他类。这使得分离算法测试和线程处理测试更容易,并且测试更容易阅读。