使用CountDownLatch或循环屏障对多线程代码进行单元测试 -Xebia

20-05-16 banq

随着处理器比以往包装更多的内核,并发编程已成为最有效利用它们的最前沿。但是,事实是并发程序的设计,编写,测试和维护要困难得多。因此,如果我们毕竟可以为并发程序编写有效且自动化的测试用例,则可以解决其中的大部分问题。

CountDownLatch

@Test
public void should_publish_an_article_using_count_down_latch_to_fix() throws InterruptedException {
    //Arrange
    Article article = Article.newBuilder()
            .withBody("learning how to test multithreaded java code")
            .withId(1)
            .withTitle("title").build();

    CountDownLatch countDownLatch = new CountDownLatch(1);
    when(this.articleRepository.findById(1)).thenReturn(article);
    doAnswer(invocationOnMock -> {
        System.out.println("Sending mail !!!");
        countDownLatch.countDown();
        return null;
    }).when(this.emailSender).sendEmail(anyString(), anyString());

    //Act
    boolean publish = this.articlePublisher.publish(1);

    //Assert
    assertThat(publish).isTrue();
    verify(this.articleRepository).findById(1);
    countDownLatch.await();
    verify(this.emailSender).sendEmail("Article Published With Id " + 1
            , "Published an article with Article Title " + "title");
    verifyNoMoreInteractions(this.articleRepository, this.emailSender);
}

我们使用CountDownLatch,以便主线程应等待,直到调用send email方法。我们调用countDownLatch的countDown方法进行暂停倒计时,直至awat()方法唤醒。

使用循环屏障Cyclic Barrier

@Test
public void should_publish_an_article_using_cyclic_barrier_to_fix() throws BrokenBarrierException, InterruptedException {
    //Arrange
    Article article = Article.newBuilder()
            .withBody("learning how to test multithreaded java code")
            .withId(1)
            .withTitle("title").build();

    CyclicBarrier cyclicBarrier = new CyclicBarrier(2, () -> System.out.println("Barrier opening"));
    when(this.articleRepository.findById(1)).thenReturn(article);
    doAnswer(invocationOnMock -> {
        System.out.println("sending mail !!!");
        cyclicBarrier.await();
        return null;
    }).when(this.emailSender).sendEmail(anyString(), anyString());
    //Act
    boolean publish = this.articlePublisher.publish(1);

    //Assert
    assertThat(publish).isTrue();
    verify(this.articleRepository).findById(1);
    cyclicBarrier.await();
    verify(this.emailSender).sendEmail("Article Published With Id " + 1
            , "Published an article with Article Title " + "title");
    verifyNoMoreInteractions(this.articleRepository, this.emailSender);
}

循环屏障使这两个并发任务同步进行。当emailSender线程的sendEmail方法和主线程同步时,将打开屏障。

随着线程数量的增加,它们可能交错的方式也呈指数增长。根本不可能弄清楚所有这样的交错并对其进行测试。我们必须依靠工具为我们进行相同或相似的工作。幸运的是,其中有一些工具可以使我们的生活更轻松。

 

              

猜你喜欢