【问题标题】:How to test ScheduledExecutorService exception handling in Junit?如何在 Junit 中测试 ScheduledExecutorService 异常处理?
【发布时间】:2017-08-01 00:35:13
【问题描述】:

我有一个计划每 30 分钟运行一次的任务。我使用 ScheduledExecutorService 进行调度。

我想测试(junit)ScheduledExecutorService 的异常处理,这样当抛出异常时,线程不会因为异常而死亡。

我的代码:

public enum MonitorTask {
    TIMER;
    private final AtomicBoolean isPublishing = new AtomicBoolean(false);
    private final long          period       = 18000000

    public synchronized boolean initialize() {
        return initialize(period, period);
    }

    /**
     * @return true, if call was successful i.e. Timer task was scheduled
     */
    boolean initialize(long delay, long period) {
        if (isPublishing.get()) {
            log.warn("Already monitoring for new feature data");
            return false;
        }

        //execute on daemon thread
        ScheduledExecutorService scheduledExecutorService =
                Executors.newSingleThreadScheduledExecutor(runnable -> {
                    Thread thread = new Thread(runnable);
                       thread.setDaemon(true);
                       return thread;
                  }
                );

        Runnable runnableTask = () -> {
            try {
                DataPublisher.INSTANCE.update(DateTime.now());
            } catch (Throwable e) {
                log.warn("Failed to check for new Data!", e);
            }
        };    

        scheduledExecutorService.scheduleAtFixedRate(runnableTask, delay, period, TimeUnit.MILLISECONDS);
        isPublishing.set(true);
        return true;
    }
}

目前,我的单元测试检查功能:

public class MonitorTaskTest {    
    @Test
    public void testInitialize() throws Exception {
        AtomicInteger val = new AtomicInteger(0);
        DataProvider provider = testProvider(val);
        assertEquals(0, val.get());
        // this should update val  every 10 ms ( adds 1 to val )
        Assert.assertTrue(MonitorTask.TIMER.initialize(0, 10));
        assertEquals(0, val.get());
        DataPublisher.INSTANCE.registerForNewData(provider, DateTime.now());
        // wait for 3 updates
        Thread.sleep(10 * 3);
        Assert.assertTrue("Expected val to be >= 3 but is " + val.get(), val.get() >= 3);
    }

    @Before
    public void setUp() {
        DataPublisher.INSTANCE.clear();
    }

    private static DataProvider testProvider(final AtomicInteger ai) {
        return new DataProvider() {
            private AtomicInteger val = ai;

            @Override public boolean update(DateTime dateTime) throws Exception {
                val.incrementAndGet();
                return true;
            }

            @Override public boolean exists(DateTime dateTime) {
                return true;
            }

            @Override public void close() throws Exception {

            }
        };
    }
}

【问题讨论】:

    标签: java multithreading junit scheduledexecutorservice


    【解决方案1】:

    我认为你在这里走错了兔子洞。含义:当你检查javadoc你正在使用的方法时,你会发现:

    创建一个单线程执行程序,可以安排命令在给定延迟后运行,或定期执行。 (但是请注意,如果这个单线程在关闭之前的执行过程中由于失败而终止,如果需要执行后续任务,新的线程将取代它。)

    换句话说:您是在询问如何测试保证可以由您正在使用的 Java 系统库工作的东西。从这个意义上说,你是在浪费时间。

    可能宁愿花时间改进您的代码以使其更易于测试。您会看到 - 当您的班级接收一个 ExecutorService 对象(而不是为自己创建一个)时,您可以传入 same thread executor 进行单元测试。突然之间,您的单元测试可以在 一个 线程上运行,这使整个测试变得更加容易 - 因为它可以让您摆脱 sleep 语句测试。 (尽管系统库保证您会这样做,但这些 sleep 语句比线程没有重新启动的可能性要大得多

    除此之外:您的可运行对象已经以一种方式编写,应该保证运行此代码的线程永远死掉(当然,它是有问题的 em> 来捕捉 Throwable)。但为了测试它,我猜你需要另一个“测试提供者”,update() 会抛出任何类型的异常。

    【讨论】:

    • 当它说“单线程终止”时,它是否也包括运行时异常?我的意思是我想确保它不会在出现运行时异常时杀死线程。
    • 我增强了我的回答。希望对您有所帮助。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-05-11
    • 2017-06-18
    • 1970-01-01
    • 1970-01-01
    • 2018-07-20
    • 2011-01-28
    相关资源
    最近更新 更多