Почему мои тесты DBUnit потребляют так много памяти?

StackOverflow https://stackoverflow.com/questions/1109466

Вопрос

У меня есть приложение на основе спящего режима, которое использует DBUnit для модульного тестирования.У нас есть тестовая база данных XML, которая загружается фиктивными данными в setUp() каждого теста и удаляется во время TearDown().Проблема в том, что я больше не могу запускать весь пакет в IDE (в данном случае в Intellij), потому что примерно после 300 тестов вся куча памяти исчерпывается.Выполнение тестов варьируется от ~0,3 секунды до 30+ секунд, пока JVM в конечном итоге не сдастся и не умрет.

Когда я запускаю набор тестов через задачу junit ant, это не проблема, и набор тестов не запускается для отдельного класса.Тем не менее, мне нравится иметь возможность запустить весь пакет локально, прежде чем вносить в базу кода крупные изменения в результате рефакторинга, вместо того, чтобы ломать сборку на CI-сервере.

Я запускаю набор тестов с -Xmx512m в качестве единственного аргумента для JVM, что соответствует тому же количеству, которое я передаю ant при запуске задачи на сервере CI.Мой hibernate-test.cfg.xml выглядит так:

<hibernate-configuration>
  <session-factory>
    <!-- Database connection settings -->
    <property name="connection.driver_class">org.hsqldb.jdbcDriver</property>
    <property name="connection.url">jdbc:hsqldb:mem:mydatabase</property>
    <property name="connection.username">sa</property>
    <property name="connection.password"/>

    <!-- Other configuration properties -->
    <property name="connection.pool_size">1</property>
    <property name="jdbc.batch_size">20</property>
    <property name="connection.autocommit">true</property>
    <property name="dialect">org.hibernate.dialect.HSQLDialect</property>
    <property name="current_session_context_class">thread</property>
    <property name="cache.provider_class">org.hibernate.cache.HashtableCacheProvider</property>
    <property name="bytecode.use_reflection_optimizer">false</property>
    <property name="show_sql">true</property>
    <property name="hibernate.hbm2ddl.auto">create-drop</property>

    <!-- Mappings (omitted for brevity) -->
    <mapping resource="hbm/blah.hbm.xml"/>
  </session-factory>
</hibernate-configuration>

Мы написали класс, от которого наследуются все тестовые классы, который выглядит примерно так:

package com.mycompany.test;
// imports omitted for brevity

public abstract class DBTestCase extends TestCase {

  private final String XML_DATA_SET = "test/resources/mytestdata.xml";
  private Session _session;
  private Configuration _config;

  public DBTestCase(String name) {
    super(name);
  }

  @Override
  protected void setUp() throws Exception {
    super.setUp();
    _config = new Configuration().configure();
    SessionFactory sf = _config.buildSessionFactory();
    // This is a singleton which is used the DAO's to acquire a session.
    // The session must be manually set from the test's setup so that any
    // calls to the singleton return this session factory, otherwise NPE
    // will result, since the session factory is normally built during
    // webapp initialization.
    HibernateUtil.setSessionFactory(sf);
    _session = sf.openSession();
    _session.beginTransaction();

    IDataSet dataSet = new FlatXmlDataSet(new File(XML_DATA_SET));
    DatabaseOperation.CLEAN_INSERT.execute(getConnection(), dataSet);
  }

  protected void tearDown() throws Exception {
    super.tearDown();
    _session.close();
  }

  protected IDatabaseConnection getConnection() throws Exception {
    ConnectionProvider connProvider = ConnectionProviderFactory
      .newConnectionProvider(_config.getProperties());
    Connection jdbcConnection = connProvider.getConnection();
    DatabaseConnection dbConnection = new DatabaseConnection(jdbcConnection);
    DatabaseConfig dbConfig = dbConnection.getConfig();
    dbConfig.setProperty(DatabaseConfig.PROPERTY_DATATYPE_FACTORY, new HsqldbDataTypeFactory());
    return dbConnection;
  }
}

Понятно, что здесь происходит какая-то утечка памяти, но где именно, я не знаю.Как я могу это диагностировать?

Это было полезно?

Решение 2

Ответ J-16 SDiZ заставил меня работать в правильном направлении, но я подумал, что предоставлю немного более подробную информацию о том, как мне удалось решить эту проблему.Корень проблемы действительно заключался в том, что база данных продолжала храниться в памяти, но решение состояло в том, чтобы наследовать от класса DBTestCase DBUnit, а не пытаться создать свой собственный, наследуя от JUnit TestCase.Базовый класс моего тестового примера теперь выглядит примерно так:

public class MyTestCase extends DBTestCase {
  private static Configuration _config = null;

  public MyTestCase(String name) {
    super(name);
    if(_config == null) {
      _config = new Configuration().configure();
      SessionFactory sf = _config.buildSessionFactory();
      HibernateUtil.setSessionFactory(sf);
    }

    System.setProperty(PropertiesBasedJdbcDatabaseTester.DBUNIT_DRIVER_CLASS, "org.hsqldb.jdbcDriver");
    System.setProperty(PropertiesBasedJdbcDatabaseTester.DBUNIT_CONNECTION_URL, "jdbc:hsqldb:mem:mydbname");
    System.setProperty(PropertiesBasedJdbcDatabaseTester.DBUNIT_USERNAME, "sa");
    System.setProperty(PropertiesBasedJdbcDatabaseTester.DBUNIT_PASSWORD, "");
  }

  @Override
  protected IDataSet getDataSet() throws Exception {
    return new FlatXmlDataSet(new FileReader(MY_XML_DATA_FILE_NAME), false, true, false);
  }

  @Override
  protected void setUpDatabaseConfig(DatabaseConfig config) {
    config.setProperty(DatabaseConfig.PROPERTY_DATATYPE_FACTORY, new HsqldbDataTypeFactory());
  }

Этот класс работает довольно хорошо, и продолжительность выполнения моего набора тестов сократилась с нескольких минут до всего лишь 30 секунд.

Другие советы

Здесь вы используете базу данных памяти:

<property name="connection.driver_class">org.hsqldb.jdbcDriver</property>
<property name="connection.url">jdbc:hsqldb:mem:mydatabase</property>

Это означает, что все, что есть в базе данных, находится в памяти.Либо используйте базу данных на диске с кэшированной таблицей, либо удаляйте все после каждого теста.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top