猿问

如何在 JMockit 中正确模拟私有 ExecutorService 的提交方法

我有一个包含私有 ExecutorService 实例的类。在类中,我有一个方法运行提交方法并捕获 RejectedExecutionException。但是,我在模拟 ExecutorService 实例以引发异常以便我可以完成测试覆盖率时遇到了麻烦。我正在使用 JMockit 1.45。


我已经浏览过 JMockit 教程和其他网站;无论我使用@Mocked、@Capturing,还是创建一个新的假类,它似乎都不起作用。


// Implemented Class:

public class TaskRegister {


    private ExecutorService executor;


    public TaskRegister() {

        this.executor = Executors.newFixedThreadPool(5);

    }


    public void executeTask(Runnable task) {

        try {

            this.executor.submit(task);

        } catch (RejectedExecutionException e) {

            System.out.println(e.getMessage);

        }

    }

}



// Unit Test Class:

public class TestTaskRegister {

    @Tested

    private TaskRegister tested;


    private static int counter;


    @Test // this works

    public void runNormalTask() throws InterruptedException {

        counter = 0;

        Runnable mockTask = new Runnable() {

            counter++;

        }


        tested.executeTask(mockTask);

        Thread.sleep(100); // Allow executor to finish other thread.

        assertEquals(1, counter);

    }


    @Test // this doesn't work, will have missing invocation error.

    public void throwsError (@Capturing ExecutorService executor) throws InterruptedException {

        counter = 0;


        // somehow the tested class still runs the actual executor 

        // and not the mocked one.

        new Expectations() {{

             executor.submit((Runnable) any);

             result = new RejectedExecutionException();

        }};


        Runnable mockTask = new Runnable() {

            // some task

        }


        tested.executeTask(mockTask);

        Thread.sleep(100);

        assertEquals(0, counter);

    }

}

我希望 @Capturing 拦截真正的执行程序实现并在调用 executor.submit 时抛出异常,但它没有这样做。


江户川乱折腾
浏览 173回答 2
2回答

万千封印

模拟的@Capturing成本可能很高,并且在某些情况下可能会导致意外结果,因此(目前)所有java.*类都被排除在外。所以,java.util.concurrent.ThreadPoolExecutor在这个测试中不会被嘲笑(它可以与@Mocked)。实际上,RejectedExecutionException异常永远不会发生(至少不会发生ThreadPoolExecutor- 可能只会发生ForkJoinPool)。所以,这个测试不值得付出努力。事实上,由于该异常是一个,RuntimeException您可以简单地catch完全删除该块。这是(滥用)模拟库发生的坏事之一:人们有时使用它们来测试不可能的情况,因此编写无用的测试。

慕娘9325324

您可以使用Executorin 参数创建一个新的构造函数。因此,您的类将更加可配置(因为目前您只能使用一种执行器),并且您将能够通过使用模拟执行器手动实例化该类来测试该类。public class TaskRegister {    private ExecutorService executor;    public TaskRegister(ExecutorService executor) {        this.executor = executor;    }    public TaskRegister() {        this(Executors.newFixedThreadPool(5));    }    public void executeTask(Runnable task) {        try {            this.executor.submit(task);        } catch (RejectedExecutionException e) {            System.out.println(e.getMessage);        }    }}
随时随地看视频慕课网APP

相关分类

Java
我要回答