Нет AUTO COMMIT в модульном тестировании Hibernate с аннотацией JPA - PullRequest
0 голосов
/ 29 января 2012

Я пытаюсь создать модульный тест для моего кода персистентности. Я использую Hibernate с аннотациями JPA. У меня нет файла persistence.xml (который используется во всех статьях о модульном тестировании JPA). Я не хочу использовать spring или создавать файл persistence.xml, потому что у меня много классов сохраняемости, и инициализация hibernate для всех из них занимает много времени, поэтому я хочу явно добавить классы в hibernate.

Также я не могу использовать configuration.createSessionFactory(), как это рекомендовано в статьях модульного тестирования Hibernate, потому что мои DAO имеют JPA EntityManager, внедренный Spring.

Итак, я использую EntityManagerFactoryImpl:

AnnotationConfiguration configuration = new AnnotationConfiguration();

configuration.setProperty(Environment.DRIVER,"org.apache.derby.jdbc.EmbeddedDriver");
configuration.setProperty(Environment.URL,"jdbc:derby:memory:srf.derby;create=true");
configuration.setProperty(Environment.USER, "");
configuration.setProperty(Environment.DIALECT, DerbyDialect.class.getName());
configuration.setProperty(Environment.SHOW_SQL, "true");
configuration.setProperty(Environment.HBM2DDL_AUTO, "create-drop");
configuration.setProperty( Environment.AUTOCOMMIT, "true");

configuration.addAnnotatedClass(MyPersistentClass.class);

MyHibernateDAO dao = new MyHibernateDAO();

EntityManagerFactoryImpl entityManagerFactory = new EntityManagerFactoryImpl(
                                  configuration.buildSessionFactory(),
                                  PersistenceUnitTransactionType.RESOURCE_LOCAL, 
                                  true, 
                                  null, 
                                  configuration);

dao.setEntityManager(entityManagerFactory.createEntityManager());

Это выглядит нормально, но по какой-то причине никакие вставки не запускаются в db, в то время как все селекты в порядке (я показал SQL true). Похоже, что AUTOCOMMIT ложно (в производственном мире Spring управляет транзакциями). Как вы видите, я установил для конфигурации значение AUTOCOMMIT true, я даже извлекаю соединение JDBC из EntityManager и вижу в отладчике, что autocommit имеет значение true, но вставки запускаются, только если в моем модульном тесте я явно начинаю и фиксирую транзакцию.

Что я делаю не так? Как я могу сделать мой тест запущенным в autocommit?

Спасибо!

1 Ответ

0 голосов
/ 29 января 2012

Я предполагаю, что вы используете @ Transactional-annotations в вашем DAO-коде. Проблема в том, что, когда вы создаете экземпляры EntityManager и DAO вручную, нет TransactionManager или прокси-серверов, которые бы позаботились о реакции на эти аннотации, поэтому транзакция никогда не создается автоматически.

Если вы действительно хотите зафиксировать данные в своей базе данных в тестах без создания Spring ApplicationContext или без использования JUnit-бегунов Springs и т. Д., Я считаю, что вам нужно обрабатывать транзакции самостоятельно (хотя это может быть неправильно). Самый простой способ - создать базовый класс для расширения ваших тестов, например:

import javax.persistence.EntityManager;

import org.hibernate.cfg.AnnotationConfiguration;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;

public abstract class TransactionalTestBase
{
    private EntityManager em;

    protected abstract Class<?>[] getAnnotatedClasses();

    @BeforeClass
    public void setupEntityManager()
    {
        //Build your basic configuration

        AnnotationConfiguration configuration = new AnnotationConfiguration();
        //configuration.setProperty(
        //...

        //Ask the implementing class for the entity-classes
        for(Class<?> clazz : getAnnotatedClasses())
        {
            configuration.addAnnotatedClass(clazz);
        }

        //Set up your entitymanager here

    }

    @Before
    public void beforeTest()
    {
        em.getTransaction().begin();
    }

    @After
    public void afterTest()
    {
        if(em.getTransaction().getRollbackOnly())
        {
            em.getTransaction().rollback();
        }
        else
        {
            em.getTransaction().commit();
        }
    }

    @AfterClass
    public void tearDownEntityManager()
    {
        em.flush();
        em.clear();
        em.close();
        em = null;
    }
}

Обратите внимание, что по мере дальнейшего расширения классов вы можете добавлять больше аннотаций @BeforeClass, @Before и т. Д., Они будут выполняться в порядке наследования.

Если вы решили использовать Spring для тестирования, см. http://static.springsource.org/spring/docs/3.1.x/spring-framework-reference/html/testing.html

...