【问题标题】:How to write concurrent unit tests如何编写并发单元测试
【发布时间】:2016-12-20 10:47:40
【问题描述】:

Awaitility 是对并发生产代码进行单元测试的绝佳工具。

问题:有没有工具可以简化并发测试代码的编写?

假设我想测试java.util.concurrent.LinkedBlockingQueue

public class BlockingQueueTest {
    private LinkedBlockingQueue<String> out;

    @Before
    public void setUp() {
        out = new LinkedBlockingQueue<>();
    }

    @Test
    public void putThenGet() throws InterruptedException {
        // that's easy because it can be done in one thread
        out.put("Hello");

        String taken = out.take();

        assertThat(taken).isEqualTo("Hello");
    }

    @Test
    public void getBeforePut() throws InterruptedException {
        // that's more tricky because it can't be done with one thread
        ExecutorService executorService = Executors.newSingleThreadExecutor();
        executorService.submit(() -> {
            Thread.sleep(100);
            out.put("Hello");
            return null;
        });
        executorService.shutdown();

        String taken = out.take();

        assertThat(taken).isEqualTo("Hello");
    }
}

getBeforePut() 编码不好玩。有没有办法让它变得不那么难读,像这样?

@Test
public void getBeforePut2() throws InterruptedException {
    // Wanted: DSL for concurrent test-code
    Concurrently.sleep(100, TimeUnit.MILLISECONDS).andThen(() -> out.put("Hello"));

    String taken = out.take();

    assertThat(taken).isEqualTo("Hello");
}

【问题讨论】:

  • 你为什么不自己实现 Concurrently 类呢?你已经有了它应该执行的代码,现在只是重构的问题。结果将有大约 30 行代码。

标签: java unit-testing kotlin junit concurrency


【解决方案1】:

使用TestNG 对我来说是最简单的方法:

 @Test(threadPoolSize = 10, invocationCount = 15, timeOut = 1000)
 public void testPut(){
     out.put("Hello");
 }

此测试将在 10 个线程中运行 15 次,时间不应超过 1000 毫秒。

你也可以创建依赖于其他测试的测试

@Test(dependsOnMethods = "testPut")
public void testGetAfterPut{
    String taken = out.take();

    assertThat(taken).isEqualTo("Hello");
}

【讨论】:

    【解决方案2】:

    现在我正在用 kotlin 编写所有测试。借助 kotlin 测试,这既简单又有趣!

    使用线程测试时值得一提的是JUnit's @Timeout Annotation,它可以防止错误测试无限运行。

    import org.assertj.core.api.Assertions.assertThat
    import org.junit.jupiter.api.Test
    import org.junit.jupiter.api.Timeout
    import java.util.concurrent.LinkedBlockingQueue
    import kotlin.concurrent.thread
    
    class BlockingQueueKotlinTests {
        // objectUnderTest
        private val out = LinkedBlockingQueue<String>()
    
        @Test
        fun `put then get`() {
            // that's easy because it can be done in one thread
            out.put("Hello")
    
            val taken = out.take()
    
            assertThat(taken).isEqualTo("Hello")
        }
    
        @Test
        @Timeout(1)
        fun `get before put`() {
            // thanks to kotlin it's really easy to do that in another thread
            thread {
                Thread.sleep(100)
                out.put("kotlin is great!")
            }
    
            val taken = out.take()
    
            assertThat(taken).isEqualTo("kotlin is great!")
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-02-03
      • 2019-01-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多