Существует ли рекомендуемый шаблон для полного сброса базы данных в свеже-проложенную схему с 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 будет создан только один раз (или дважды, если схема была недействительной).