1

我需要对下面使用 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();
    }
}
4

1 回答 1

4

那么你想测试什么?我想你想测试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。它不关心它是否在新线程中执行,它恰好是你的情况。所以你可以单独测试这个类。如果你的代码结构良好,你将拥有处理线程组织的类,而其他类只执行工作,没有别的。这使得分离算法测试和线程处理测试更容易,测试更容易阅读。
于 2016-05-31T21:58:56.847 回答