2009-07-10 3 views
0

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

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

Я запускаю тестовый набор с -Xmx512m как единственный аргумент JVM, который является той же суммой, которую я передаю муравью при выполнении задачи на сервере CI. Моя гибернация-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; 
    } 
} 

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

ответ

0

Ответ 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 секунд.

2

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

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

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

Смежные вопросы