Как мне переустанавливать базу данных, контролируемую JPA, перед каждым тестом? - PullRequest
5 голосов
/ 10 сентября 2010

Существует ли шаблон наилучшей практики для полного сброса базы данных в недавно выложенную схему с помощью JPA перед модульным тестом? Я использовал модуль персистентности тестирования с hbml2ddl.auto = create-or-drop и воссоздаю EMF перед каждым тестом, но мне интересно, есть ли более чистый способ сделать это.

Ответы [ 4 ]

1 голос
/ 10 сентября 2010

DBUnit имеет многое из того, что вам нужно, я использую инфраструктуру Springs Testing для отката, транзакции после каждого теста см. http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/testing.html

1 голос
/ 10 сентября 2010

Сброс базы данных не является большой проблемой, если вы используете быструю базу данных Java, такую ​​как H2 база данных или HSQLDB. По сравнению с использованием Oracle / MySQL (или того, что вы используете для производства) это ускорит ваши тесты и обеспечит проверку всего вашего кода, как при использовании «реальной» производственной базы данных.

Для максимальной производительности вы можете использовать H2 в памяти (таким образом вам может не потребоваться сбросить базу данных вручную - она ​​сбрасывается автоматически, если соединение закрыто), или вы можете использовать обычную постоянную базу данных. Чтобы сбросить базу данных после использования в H2, запустите (собственный) оператор «отбросить все объекты, удалить файлы».

1 голос
/ 10 сентября 2010

Модульные тесты не должны взаимодействовать с базой данных.

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

0 голосов
/ 10 сентября 2010

Существует ли рекомендуемый шаблон для полного сброса базы данных в свеже-проложенную схему с JPA перед модульным тестом?

Не переустанавливайте всю схему БД перед каждыммодульный тест, но сбросьте «среду БД (которая является специфической для текущего модульного теста)» в КОНЦЕ каждого модульного теста.

У нас есть объект ...

@Entity
public class Candidate implements {
    private String id;
    private String userName;
    private EntityLifeCycle lifeCycle;

    protected Candidate() {
    }
    public Candidate(String userName) {
        this.userName = userName;
    }

    @Id @GeneratedValue(generator="uuid", strategy=GenerationType.AUTO)
    @GenericGenerator(name="uuid", strategy="uuid", parameters = {})
    @Column(name="candidate_id", nullable=false, unique=true)
    public String getId() {
        return id;
    }
    protected void setId(String id) {
        this.id = id;
    }

    @Column(name="user_name", nullable=false, unique=true)
    public String getUserName() {
        return userName;
    }
    public void setUserName(String userName) {
        this.userName = userName;
    }

    @Embedded
    public EntityLifeCycle getLifeCycle() {
        if(lifeCycle == null) {
            lifeCycle = new EntityLifeCycleImpl();
        }
        return lifeCycle;
    }
    public void setLifeCycle(EntityLifeCycleImpl lifeCycle) {
        this.lifeCycle = lifeCycle;
    }

    @PrePersist
    public void prePersist() {
         lifeCycle.setCreatedDate(new Date());
    }
}

Мыустанавливаем createDate для каждого экземпляра Candidate в методе prePersist ().Вот тестовый пример, который утверждает, что createDate устанавливается правильно ....

   public class EntityLifeCycleTest {
    @Test
    public void testLifeCycle() {
        EntityManager manager = entityManagerFactory.createEntityManager();
        Candidate bond = new Candidate("Miss. Bond");
        EntityTransaction tx = manager.getTransaction();
        tx.begin();
        manager.persist(bond);
        tx.commit();

        Assert.assertNotNull(bond.getLifeCycle().getCreatedDate());
        manager.close();
    }
}

Этот тестовый пример будет работать правильно в первый раз.Но если мы запустим этот тестовый случай во второй раз, он выдаст ConstraintViolationException, потому что userName является уникальным ключом.

Поэтому я думаю, что правильный подход - это «очистить среду БД (которая характерна для текущего модульного теста»).) "в конце каждого теста.Вот так ...

public class EntityLifeCycleTest extends JavaPersistenceTest {
    @Test
    public void testLifeCycle() {
        EntityManager manager = entityManagerFactory.createEntityManager();
        Candidate bond = new Candidate("Miss. Bond");
        EntityTransaction tx = manager.getTransaction();
        tx.begin();
        manager.persist(bond);
        tx.commit();

        Assert.assertNotNull(bond.getLifeCycle().getCreatedDate());

      /* delete Candidate bond, so next time we can run this test case successfully*/
        tx = manager.getTransaction();
        tx.begin();
        manager.remove(bond);
        tx.commit();
        manager.close();
    }
}

Я использовал модуль персистентности тестирования с hbml2ddl.auto = create-or-drop и воссоздаю EMF перед каждым тестом, но мне интересно, есть ли более чистый способчтобы сделать это.

Воссоздание EMF перед каждым тестом отнимает много времени, IMO.

Удаление и повторное создание схемы БД, только если вы внесли некоторые изменения в аннотированный класс @Entity, которые влияют набазовая БД (например, добавление / удаление столбцов и / или ограничений).Поэтому сначала проверьте схему, если схема действительна, не воссоздайте ее, а если она недействительна, воссоздайте ее.Вот так ...

public class JavaPersistenceTest {
    protected static EntityManagerFactory entityManagerFactory;
@BeforeClass
public static void setUp() throws Exception {
    if(entityManagerFactory == null) {
         Map<String, String> properties = new HashMap<String, String>(1);
         try {
           properties.put("hibernate.hbm2ddl.auto", "validate");
          entityManagerFactory = Persistence.createEntityManagerFactory("default", properties);
    } catch (PersistenceException e) {
        e.printStackTrace();
        properties.put("hibernate.hbm2ddl.auto", "create");
        entityManagerFactory = Persistence.createEntityManagerFactory("default", properties);
    }
         }
}
}

Теперь, если вы запустите все тесты (которые расширяют JavaPersistenceTest) за один раз, EMF будет создан только один раз (или дважды, если схема была недействительной).

...