0

単体テストに DBUnit を使用する休止状態ベースのアプリケーションがあります。各テストの setUp() でダミー データが読み込まれ、tearDown() で削除される XML テスト データベースがあります。問題は、IDE (この場合は Intellij) でスイート全体を実行できなくなったことです。これは、約 300 回のテストの後、ヒープ メモリが使い果たされるためです。JVM が最終的にあきらめて停止するまで、テストの実行には約 0.3 秒から 30 秒以上かかります。

ant の junit タスクを介してテスト スイートを実行すると、問題はなく、個々のクラスのテスト スイートも実行されません。ただし、CI サーバーでビルドを壊すのではなく、大規模なリファクタリングの変更をコードベースにチェックインする前に、スイート全体をローカルで実行できるのが気に入っています。

JVM への唯一の引数として -Xmx512m を使用してテスト スイートを実行しています。これは、CI サーバーでタスクを実行するときに ant に渡すのと同じ量です。私の 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;
  }
}

ここでメモリ リークが発生していることは明らかですが、どこで発生しているのかはわかりません。これを診断するにはどうすればよいですか?

4

2 に答える 2

2

ここでメモリデータベースを使用しています:

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

つまり、データベース内のすべてがメモリ内にあるということです。キャッシュされたテーブルでディスクデータベースを使用するか、各テストの後にすべてを削除してください。

于 2009-07-10T13:25:37.937 に答える
0

J-16 SDiZの答えは私を正しい方向に向かわせましたが、私がこれをどのように解決できたかについて、もう少し詳細な情報を提供したいと思いました。問題の根本は確かにデータベースがメモリに格納され続けることでしたが、解決策はDBUnitのDBTestCaseクラスから継承することであり、JUnitTestCaseから継承することによって自分自身をロールしようとはしませんでした。私のテストケースの基本クラスは次のようになります。

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秒に短縮されました。

于 2009-07-22T19:20:08.260 に答える