Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/363.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 在每次测试之前,我应该如何重置JPA控制的数据库?_Java_Hibernate_Testing_Jpa_Integration Testing - Fatal编程技术网

Java 在每次测试之前,我应该如何重置JPA控制的数据库?

Java 在每次测试之前,我应该如何重置JPA控制的数据库?,java,hibernate,testing,jpa,integration-testing,Java,Hibernate,Testing,Jpa,Integration Testing,在单元测试之前,是否有一种最佳实践模式可以使用JPA将数据库完全重置为新构建的模式?我一直在使用hbml2ddl.auto=在每次测试之前创建或删除并重新创建EMF的测试持久性单元,但我想知道是否有更干净的方法来执行此操作。单元测试不应与数据库对话 假设您正在为数据访问层编写集成测试,您可以使用类似的工具,也可以创建一个静态测试帮助器,通过在事务中使用JPA查询执行所有删除和插入操作,以编程方式重置数据库状态 如果使用快速Java数据库(如或HSQLDB),则重置数据库不是一个大问题。与使用Or

在单元测试之前,是否有一种最佳实践模式可以使用JPA将数据库完全重置为新构建的模式?我一直在使用hbml2ddl.auto=在每次测试之前创建或删除并重新创建EMF的测试持久性单元,但我想知道是否有更干净的方法来执行此操作。

单元测试不应与数据库对话


假设您正在为数据访问层编写集成测试,您可以使用类似的工具,也可以创建一个静态测试帮助器,通过在事务中使用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?在每次测试之前,你是如何重新创建的?