Java 在每次测试之前,我应该如何重置JPA控制的数据库?
在单元测试之前,是否有一种最佳实践模式可以使用JPA将数据库完全重置为新构建的模式?我一直在使用hbml2ddl.auto=在每次测试之前创建或删除并重新创建EMF的测试持久性单元,但我想知道是否有更干净的方法来执行此操作。单元测试不应与数据库对话Java 在每次测试之前,我应该如何重置JPA控制的数据库?,java,hibernate,testing,jpa,integration-testing,Java,Hibernate,Testing,Jpa,Integration Testing,在单元测试之前,是否有一种最佳实践模式可以使用JPA将数据库完全重置为新构建的模式?我一直在使用hbml2ddl.auto=在每次测试之前创建或删除并重新创建EMF的测试持久性单元,但我想知道是否有更干净的方法来执行此操作。单元测试不应与数据库对话 假设您正在为数据访问层编写集成测试,您可以使用类似的工具,也可以创建一个静态测试帮助器,通过在事务中使用JPA查询执行所有删除和插入操作,以编程方式重置数据库状态 如果使用快速Java数据库(如或HSQLDB),则重置数据库不是一个大问题。与使用Or
假设您正在为数据访问层编写集成测试,您可以使用类似的工具,也可以创建一个静态测试帮助器,通过在事务中使用JPA查询执行所有删除和插入操作,以编程方式重置数据库状态 如果使用快速Java数据库(如或HSQLDB),则重置数据库不是一个大问题。与使用Oracle/MySQL(或用于生产的任何工具)相比,这将加快测试速度,并确保所有代码都像使用“真实”生产数据库时一样经过测试 为了获得最佳性能,您可以在内存中使用H2(这样您就不必手动重置数据库-如果连接关闭,它会自动重置),或者您可以使用常规的持久数据库。要在H2中使用后重置数据库,请运行(本机)语句“dropall objects delete files” 在单元测试之前,是否有一种最佳实践模式可以使用JPA将数据库完全重置为新构建的模式 不要在每个单元测试之前重置整个DB模式,而是在每个单元测试结束时重置“DB环境(特定于当前单元测试)” 我们有一个实体
@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());
}
}
我们正在prePersist()方法中为每个候选实例设置createdDate。下面是一个测试用例,它断言createdDate设置正确
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,因为用户名是唯一的密钥
因此,我认为正确的方法是在每个测试用例结束时“清理DB环境(特定于当前单元测试)”。像这样
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();
}
}
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);
}
}
}
}
在每次测试之前,我一直在使用hbml2ddl.auto=create或drop并重新创建EMF的测试持久性单元,但我想知道是否有更干净的方法来做这件事
IMO认为,在每次测试之前重新创建EMF非常耗时
只有在对@Entity注释类进行了一些影响基础数据库的更改(例如添加/删除列和/或约束)时,才能删除并重新创建数据库架构。因此,首先验证模式,如果模式有效,则不要重新创建它,如果无效,则重新创建它。像这样
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();
}
}
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{
受保护的静态EntityManager工厂EntityManager工厂;
@课前
public static void setUp()引发异常{
if(entityManagerFactory==null){
映射属性=新的HashMap(1);
试一试{
properties.put(“hibernate.hbm2ddl.auto”、“validate”);
entityManagerFactory=Persistence.createEntityManagerFactory(“默认”,属性);
}捕获(持久异常e){
e、 printStackTrace();
properties.put(“hibernate.hbm2ddl.auto”、“create”);
entityManagerFactory=Persistence.createEntityManagerFactory(“默认”,属性);
}
}
}
}
现在,如果您一次性运行所有测试用例(扩展JavaPersistenceTest),EMF将只创建一次(如果模式无效,则创建两次)。DBUnit有很多您需要的东西,我使用Springs测试框架回滚,每次测试后的事务请参见您能证明您的初始断言正确吗?我猜理由是“因为数据库速度慢”。在使用Oracle等应用程序时也是如此,即使打开连接也很慢。内存数据库不是这样,我想理由是“单元”测试应该单独测试“单元”。一旦涉及到数据库,就不再进行单元测试,而是进行集成测试。我原则上同意单元测试通常不与数据库连接,但我还要补充一点,单元测试不应该跨越进程边界。因此,如果您需要在另一个进程中启动数据库,那么您就进入了集成测试的领域。但是,如果在让内存中的数据库为您工作方面付出最小的努力,那么这样做可能比使用mock更便宜。如果它与数据库交互,则不称为单元测试,而是集成测试。一旦你进入了这种心态,你就会意识到单元测试并没有你以前想象的那么有用。给定的“单元测试”一次只测试一个方法/类。如果您的测试链接到其他“单元”,则它是集成测试或系统测试。集成测试也经常与JUnit一起运行,所以它们经常被称为单元测试。我不同意,@PascalThivent这并不总是正确的。例如,如果有一个findAll()方法的测试,并且我希望确保数据库中没有比我预期的更多的记录,那么是的,我希望在此测试之前清理所有其他记录。即使那个数据库是我的,我也会尽可能地保持清晰。你如何强制关闭连接?H2数据库不会验证你的代码是否能在生产数据库上工作,因为H2与mysql数据库在多个方面不同。@Maaaa我想如果有人使用JPA,那么他会想编写与数据库类型无关的代码。换句话说,H2和MySQL确实有不同的行为,但不同版本的Java也有不同的行为?什么是EMF?在每次测试之前,你是如何重新创建的?