【问题标题】:Scheduler works incorrect in unit testing调度程序在单元测试中工作不正确
【发布时间】:2019-11-17 13:46:51
【问题描述】:

我需要从公共 API 收集数据。我想每天或每天收集两次。

public class AlphavantageStockRequestDispatcher {
    public static void startAlphavantageStockScraper(int timeInterval) {
        ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);

        Runnable getStockList =
                new Runnable() {
                    @Override
                    public void run() {
                        List<AlphavantageStock> stocks = AlphavantageStockRequest.getStockPrices(); //Method contains requests

                        StockDao<AlphavantageStock> dao = new JpaAlphavantageStockDao();

                        for (AlphavantageStock stock : stocks) {
                            dao.save(stock);
                        }
                    }
                };

        scheduler.scheduleAtFixedRate(getStockList, 0, timeInterval, TimeUnit.HOURS);
    }
}

问题是当我从同一个类启动它时(只是添加了 main 方法并调用了startAlphavantageStockScraper(1); 它工作正常。但是当我想通过 JUnit 测试它时它不起作用(测试类在对称包名称中但 @ 987654323@子文件夹):

public class AlphavantageStockRequestDispatcherTest {
    @Test
    public void startDispatcher_TwoFullCycles_WithOneHourIntervalBetween() {
        AlphavantageStockRequestDispatcher.startAlphavantageStockScraper(1);
    }
}

在调试时我发现在单元测试执行中程序到达public void run() 行然后跳过它。所以没有错误。程序正确结束,但没有任何用处。

任何帮助将不胜感激。

【问题讨论】:

    标签: java multithreading junit scheduled-tasks runnable


    【解决方案1】:

    这就是异步编程的工作原理。在AlphavantageStockRequestDispatcher 课程中,您刚刚提交了一个任务,但您必须等待它完成。有几种方法可以处理这种情况。我更喜欢使用java.util.concurrent.CountDownLatch 的状态通知。所以建议在AlphavantageStockRequestDispatcher 类中进行一些重构,如下所示:

    
    public class AlphavantageStockRequestDispatcher {
        public static void startAlphavantageStockScraper(int timeInterval, CountDownLatch latch) {
            ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
    
            Runnable getStockList =
                    new Runnable() {
                        @Override
                        public void run() {
                            System.out.println("worker started");
                            try {
                                Thread.sleep(10_000L);
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            } finally {
                                System.out.println("worker finished");
                                Optional.ofNullable(latch).ifPresent(CountDownLatch::countDown);
                            }
                        }
                    };
    
            scheduler.scheduleAtFixedRate(getStockList, 0, timeInterval, TimeUnit.HOURS);
    
        }
    
    }
    
    

    现在可以测试了。

    public class AlphavantageStockRequestDispatcherTest {
    
        @Test
        void startDispatcher_TwoFullCycles_WithOneHourIntervalBetween() throws InterruptedException {
            CountDownLatch latch = new CountDownLatch(1);
            AlphavantageStockRequestDispatcher.startAlphavantageStockScraper(1, latch);
            latch.await(20, TimeUnit.SECONDS);
            System.out.println("first finished - need some assertions");
        }
    
    }
    
    

    【讨论】:

    • 谢谢,它似乎工作。但奇怪的是我必须修改方法的签名只是为了对其进行单元测试。
    • 不,你只需要修改方法体来跟踪后台线程状态。等待就足够了,例如测试方法中的 20 秒,但我认为这是最脏的方法之一。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-06-21
    • 1970-01-01
    • 2022-08-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多