8

我尝试使用 Mockito 来模拟数据库池(仅用于检索数据),但是当运行在一段时间内检索到许多模拟连接的性能测试时,它的内存不足。

这是一个简化的自包含代码,它在我的机器上进行了大约 150,000 次循环迭代后抛出 OutOfMemoryError(尽管似乎没有全局保存任何内容,并且所有内容都应该是可回收的)。我究竟做错了什么?

import static org.mockito.Mockito.when;

import java.sql.Connection;

import org.mockito.Mock;
import org.mockito.MockitoAnnotations;

public class Test1 {

    static class DbPool {
        public Connection getConnection() {return null;}
    }

    @Mock
    private DbPool dbPool;

    @Mock
    private Connection connection;

    public Test1() {
        MockitoAnnotations.initMocks(this);
        when(dbPool.getConnection()).thenReturn(connection);

        for(int i=0;i<1000000;i++) {
            dbPool.getConnection();
            System.out.println(i);
        }
    }

    public static void main(String s[]) {       
        new Test1();
    }
}
4

2 回答 2

19

david-wallace 的回复解释了您遇到 OOM 的原因:一个模拟对象正在记住每次调用的细节。

但同样重要的问题是:现在该怎么办?除了 David 已经提出的建议之外,最新的 Mockito 版本 1.10.19 以及即将推出的 2.0.x 现在支持所谓的模拟stubOnly(参见javadoc):

stubOnly:仅存根模拟不记录方法调用,从而节省内存但不允许验证调用。

Scala 使用示例:

import org.mockito.Mockito
val list = Mockito.mock(classOf[Foo], Mockito.withSettings().stubOnly())

// The syntax is a bit more concise when using ScalaTest's MockitoSugar
val foo = mock[Foo](Mockito.withSettings().stubOnly())

Java 使用示例(未经测试):

import org.mockito.Mockito;
Foo mock = Mockito.mock(Foo.class, Mockito.withSettings().stubOnly());
于 2015-03-03T14:01:09.340 回答
15

问题是模拟对象会记住每次调用的细节,以防您以后想验证它。最终,它将不可避免地耗尽内存。您需要做的是偶尔使用Mockito.reset静态方法重置模拟,然后再次存根您的方法。不幸的是,如果不重新设置存根,就无法清除模拟的验证信息。

此问题在https://code.google.com/p/mockito/issues/detail?id=84中有详细介绍

于 2013-07-03T03:33:15.883 回答