使用CountDownLatch或迴圈屏障對多執行緒程式碼進行單元測試 -Xebia

banq發表於2020-05-16

隨著處理器比以往包裝更多的核心,併發程式設計已成為最有效利用它們的最前沿。但是,事實是併發程式的設計,編寫,測試和維護要困難得多。因此,如果我們畢竟可以為併發程式編寫有效且自動化的測試用例,則可以解決其中的大部分問題。

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方法和主執行緒同步時,將開啟屏障。

隨著執行緒數量的增加,它們可能交錯的方式也呈指數增長。根本不可能弄清楚所有這樣的交錯並對其進行測試。我們必須依靠工具為我們進行相同或相似的工作。幸運的是,其中有一些工具可以使我們的生活更輕鬆。



 

相關文章