Статьи

Минимальная конфигурация для тестирования Hibernate

Вступление

В своем предыдущем посте я объявил о своем намерении создать персональный курс Hibernate. Первое, с чего нужно начать — это минимальная конфигурация тестирования. Примеры актуальны для Hibernate 4 .

Вам нужен только Hibernate

В реальной производственной среде вы не будете использовать только Hibernate, поскольку можете интегрировать его в контейнер JEE или Spring. Для тестирования функций Hibernate вам не нужен полноценный стек фреймворка, вы можете просто положиться на гибкие параметры конфигурации Hibernate.

Случай 1: Конфигурация JDBC на основе драйвера

Сначала мы определяем тестовую сущность:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
@Entity
class SecurityId {
    @Id
    @GeneratedValue
    private Long id;
 
    private String role;
 
    public Long getId() {
        return id;
    }
 
    public String getRole() {
        return role;
    }
 
    public void setRole(String role) {
        this.role = role;
    }
}

Благодаря уровню абстракции Hibernate Transaction мы не вынуждены нанимать какого-либо внешнего менеджера транзакций или писать какой-либо самодельный код управления транзакциями.

В целях тестирования мы можем использовать локальные транзакции ресурса JDBC, которые внутренне управляются JdbcTransactionFactory по умолчанию.

Нам даже не нужно предоставлять внешний источник данных, поскольку Hibernate поставляется с непроизводственным встроенным пулом соединений, представленным DriverManagerConnectionProviderImpl .

Наш тестовый код выглядит так:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
@Test
public void test() {
    Session session = null;
    Transaction txn = null;
    try {
        session = sf.openSession();
        txn = session.beginTransaction();
 
        SecurityId securityId = new SecurityId();
        securityId.setRole("Role");
        session.persist(securityId);
 
        txn.commit();
    } catch (RuntimeException e) {
        if ( txn != null && txn.isActive() ) txn.rollback();
        throw e;
    } finally {
        if (session != null) {
            session.close();
        }
    }
}

Нам не нужен внешний файл конфигурации, поэтому мы можем построить и настроить фабрику сессий:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
@Override
protected SessionFactory newSessionFactory() {
    Properties properties = new Properties();
    properties.put("hibernate.dialect", "org.hibernate.dialect.HSQLDialect");
    //log settings
    properties.put("hibernate.hbm2ddl.auto", "update");
    properties.put("hibernate.show_sql", "true");
    //driver settings
    properties.put("hibernate.connection.driver_class", "org.hsqldb.jdbcDriver");
    properties.put("hibernate.connection.url", "jdbc:hsqldb:mem:test");
    properties.put("hibernate.connection.username", "sa");
    properties.put("hibernate.connection.password", "");
 
    return new Configuration()
            .addProperties(properties)
            .addAnnotatedClass(SecurityId.class)
            .buildSessionFactory(
                    new StandardServiceRegistryBuilder()
                            .applySettings(properties)
                            .build()
    );
}

Случай 2: использование профессионального пула соединений

Если мы хотим заменить встроенный пул соединений профессиональным, Hibernate предлагает выбор настройки c3p0, которая обрабатывается внутри C3P0ConnectionProvider .

Нам нужно только изменить свойства конфигурации фабрики сеанса:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
protected SessionFactory newSessionFactory() {
    Properties properties = new Properties();
    properties.put("hibernate.dialect", "org.hibernate.dialect.HSQLDialect");
    //log settings
    properties.put("hibernate.hbm2ddl.auto", "update");
    properties.put("hibernate.show_sql", "true");
    //driver settings
    properties.put("hibernate.connection.driver_class", "org.hsqldb.jdbcDriver");
    properties.put("hibernate.connection.url", "jdbc:hsqldb:mem:test");
    properties.put("hibernate.connection.username", "sa");
    properties.put("hibernate.connection.password", "");
    //c3p0 settings
    properties.put("hibernate.c3p0.min_size", 1);
    properties.put("hibernate.c3p0.max_size", 5);
 
    return new Configuration()
            .addProperties(properties)
            .addAnnotatedClass(SecurityId.class)
            .buildSessionFactory(
                    new StandardServiceRegistryBuilder()
                            .applySettings(properties)
                            .build()
    );
}

Случай 3: Использование внешнего источника данных

Поскольку Hibernate не регистрирует подготовленные операторы SQL параметры:

1
o.h.SQL - insert into SecurityId (id, role) values (default, ?)

Мы добавим источник данных-прокси для перехвата реальных запросов SQL:

1
n.t.d.l.SLF4JQueryLoggingListener - Name: Time:0 Num:1 Query:{[insert into SecurityId (id, role) values (default, ?)][Role]}

Конфигурация выглядит так:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
@Override
protected SessionFactory newSessionFactory() {
    Properties properties = new Properties();
    properties.put("hibernate.dialect", "org.hibernate.dialect.HSQLDialect");
    //log settings
    properties.put("hibernate.hbm2ddl.auto", "update");
    //data source settings
    properties.put("hibernate.connection.datasource", newDataSource());
 
    return new Configuration()
            .addProperties(properties)
            .addAnnotatedClass(SecurityId.class)
            .buildSessionFactory(
                    new StandardServiceRegistryBuilder()
                            .applySettings(properties)
                            .build()
            );
}
 
private ProxyDataSource newDataSource() {
    JDBCDataSource actualDataSource = new JDBCDataSource();
    actualDataSource.setUrl("jdbc:hsqldb:mem:test");
    actualDataSource.setUser("sa");
    actualDataSource.setPassword("");
    ProxyDataSource proxyDataSource = new ProxyDataSource();
    proxyDataSource.setDataSource(actualDataSource);
    proxyDataSource.setListener(new SLF4JQueryLoggingListener());
    return proxyDataSource;
}

Вывод

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

  • Код доступен на GitHub .