【问题标题】:How to create a test which waits for record appearance in the database?如何创建一个等待记录出现在数据库中的测试?
【发布时间】:2017-03-29 18:32:11
【问题描述】:

我有一个方法,它开始在另一个线程中生成一些报告,而主线程返回一个指向应上传创建的报告的 google 文件夹的链接。创建报表后,它会在数据库中插入一条包含一些信息的记录。

public Link startReportCreation(ReportRequest reportRequest) {
    Link link = /** some logic **/;
    taskExecutor.execute(() -> {
        /** report creation logic **/
    });
    return link;

那么在不修改startReportCreation方法的情况下测试插入记录信息的最佳方法是什么?


更新

目前我有while (taskExecutor.getActiveCount() != 0); 类型的锁,这表明taskExecutor 结束了它的执行,我可以检查数据库。但我认为有更好的方法。


顺便说一句,这是一种误导,这不是单元测试,它只是在真实数据上手动测试方法的执行器。


已解决

所以我设法重构了我的startReportCreation 方法,而不是简单的taskExecutor 我使用CompletableFuture,所以现在它看起来像这样:

public CompletableFuture<Link> startReportCreation(ReportRequest reportRequest) {
    /** some logic **/
    return CompletableFuture.supplyAsync(() -> {
        Link link = /** some logic **/;
        return link;
    }, taskExecutor);
}

所以在生产代码中我使用CompletableFuture.getNow() 方法,在测试中我使用CompletableFuture.get() 来等待报告创建。

【问题讨论】:

    标签: java multithreading testing


    【解决方案1】:

    首先要记住单元测试的 FIRST 原则。 F:快 一:独立 R:可重复 S:小 T:及时

    您可以在这里详细查看它们:https://github.com/ghsukumar/SFDC_Best_Practices/wiki/F.I.R.S.T-Principles-of-Unit-Testing

    要达到你所需要的,你必须以这种方式准备测试:

    import org.junit.After;
    import org.junit.Before;
    import org.junit.Test;
    import static org.junit.Assert.assertTrue;
    
    public class ReportGeneratorTest {
    
        //This is executed before each @Test, generally is used for prepare the ambient, instantiate services, start servers and so on.
        @Before
        public void setUp() throws IOException {
            report = MyReportService.createReport();
        }
    
        //This is executed after each @Test generally this used for tear down your servers or data bases, or delete all the records inserted
        @After
        public void tearDown() {
            MyReportService.deleteById(10);
        }
    
        @Test
        public void verifyInsertion() throws Exception {
            //Here you can verify that the record of your serive or logic it's ok
            assertTrue(MyReportService.getLastId() > 10); //Or whatever
        }
    }
    

    编辑:

    来自并发单元的文档:https://github.com/jhalterman/concurrentunit/blob/master/src/test/java/net/jodah/concurrentunit/WaiterTest.java 您可以创建一个线程并等待它。

    @Test
    public class WaiterTest {
      @Test
      public void shouldSupportMultipleThreads() throws Throwable {
        final Waiter waiter = new Waiter();
    
        for (int i = 0; i < 5; i++)
          new Thread(new Runnable() {
            public void run() {
              waiter.assertTrue(true);
              waiter.resume();
            }
          }).start();
    
        waiter.await(0);
      }
    

    【讨论】:

    • 这不适用于我的示例,因为createReport() 方法将在另一个线程中开始创建报告,而verifyInsertion 将不会看到数据库中的任何更改。
    • 我明白了,也许这种方法可以帮助你:stackoverflow.com/questions/5336251/…
    • 但我不想在我的代码中插入那些 Waiters 只是为了测试它(而且我没有看到有人会使用它的任何情况)。
    • 是的,我想我的要求太高了,看来我需要重组代码才能正确测试它。无论如何,谢谢你的链接,对CompletionService很有帮助。
    猜你喜欢
    • 1970-01-01
    • 2022-08-12
    • 2022-12-03
    • 1970-01-01
    • 1970-01-01
    • 2021-02-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多