如何用Mockito模拟Thread.class?

时间:2017-08-16 19:49:24

标签: java mockito

作为我的单元测试的一部分,我试图模拟Thread.class isAlive()方法使用Mockito返回true。以下是我的代码:

final Thread mockThread = Mockito.mock(Thread.class);
Mockito.when(mockThread.isAlive()).thenReturn(true);

这在第二行给出了以下例外:

Exception in thread "main" org.mockito.exceptions.misusing.MissingMethodInvocationException: when() requires an argument which has to be 'a method call on a mock'. For example: when(mock.getArticles()).thenReturn(articles); Also, this error might show up because: 1. you stub either of: final/private/equals()/hashCode() methods. Those methods cannot be stubbed/verified. Mocking methods declared on non-public parent classes is not supported. 2. inside when() you don't call method on mock but on some other object.

我已经多次使用Mockito而没有问题。模拟Thread.class有一些问题吗?我没有运气就四处寻找。

4 个答案:

答案 0 :(得分:3)

使用Thread.isAlive()修饰符声明

final。它不能被Mockito 1嘲笑 使用添加this feature的Powermock或Mockito 2:

  

很长一段时间,当Mockito拒绝时,我们的用户都难以置信   嘲笑最后一堂课。   ...   最终类和方法的模拟是一个孵化,选择加入的功能

或者另一种方式:改变对班级进行单元测试的方式。

您真的需要依靠isAlive()进行单元测试吗?

如果你确实需要它,你也可以使用一个包装类来组成一个Thread实例,并将处理委托给组合Thread
例如,这可以实现Runnable 通过这种方式,您可以自然地模拟此包装类的isAlive()方法。

答案 1 :(得分:2)

正如其他人所指出的,Thread的isAlive方法是最终的,因此不能(也可能不应该)使用Mockito进行模拟。

一个简单的解决方法是在我的单元测试类中使用run()方法创建一个私有的Runnable类,该方法只调用this.wait()。

private class TestRunnable implements Runnable {
        @Override
        public void run() {
            synchronized(this) {
                try {
                    this.wait();
                } catch (InterruptedException e) {
                    System.out.println("Interrupted!");
                }
            }       
        }
    }

然后我可以使用this的实例在单元测试中创建一个线程,isAlive()方法将始终返回true。

final TestRunnable testRunnable = new TestRunnable();
final Thread expectedThread = new Thread(testRunnable);
expectedThread.start();

然后在测试中......

assertTrue(expectedThread.isAlive());

最后,要清理线程,只需在Runnable实例上调用notify()(当然,当JUnit完成时线程也将结束)

synchronized(testRunnable) {
    testRunnable.notifyAll(); // kill the Runnable (prob not necessary)
}

答案 2 :(得分:2)

我给你一个完全不同的观点:摆脱与生产代码中的线程完全交互

事情是:Thread是一个非常低级抽象的多线程。 10,15年前我们只有 主题,并因此被迫使用它们。

但是现在,你有很多种抽象在更高层次上工作,比如ExecutorServicesFutures,以及Promises,......

这可能听起来很奇怪 - 但是你可能更有帮助的是回过头来考虑 not 使用线程,就像你今天使用它们一样。您可以看到,Same-Thread-Executors等内容允许您将多线程代码转换为单个线程进行测试 - 只需提供不同的服务来执行任务即可。

这就是你应该在2017年努力的抽象层次 - 你不应该浪费时间去嘲笑低级别的最终方法!

答案 3 :(得分:1)

看起来Thread.isAlive方法是final,并且不能用Mockito模拟最终方法。

这是related stackoverflow post