之前,我在Hibernate博客上写了一篇文章,展示了如何创建一个测试用例,该测试用例可以重现某个Hibernate ORM问题。
在此期间,我意识到有更好的方法,我将在本文中解释。
hibernate-test-case-templates的缺点
尽管hibernate-test-case-templates
比自行编写测试用例并解决引导部分要好得多,但它也存在一些缺点。
-
由于托管在GitHub上,一些开发者将他们的测试用例作为
hibernate-test-case-templates
的Pull Request提交,而不是将其附加到相关的Hibernate JIRA问题。 -
作为开发者,您将无法从我们为Hibernate ORM测试套件开发的
doInJPA
或doInHibernate
实用程序中受益。 -
在各个数据库之间复制测试用例需要手动更改数据库连接配置属性。
-
Hibernate ORM开发者需要从JIRA问题中下载测试用例,并将其手动集成到Hibernate ORM项目中。然而,这也意味着我们无法将原始工作归功于测试用例的作者。
替代方案
一个可能对Hibernate ORM客户和核心开发者都更好的替代方案是,将测试用例作为对hibernate-orm
项目的Pull Request提交。
创建测试用例
现在您已经设置了hibernate-orm
项目,要创建测试用例,您应该从以下两个基类之一扩展
BaseEntityManagerFunctionalTestCase
:用于基于JPA的测试用例。BaseNonConfigCoreFunctionalTestCase
:用于需要Hibernate特定引导机制的测试用例。
让我们假设我们想要为HHH-12561 JIRA问题创建一个测试用例。
首先,我们需要创建一个新的分支
git checkout -b HHH-12561
测试用例可能如下所示
@TestForIssue( JIRAKey = "HHH-12561" )
public class GlobalQuotedIdentifiersBulkIdTest
extends BaseEntityManagerFunctionalTestCase {
@Override
protected Class<?>[] getAnnotatedClasses() {
return new Class<?>[] {
Person.class,
Doctor.class,
Engineer.class
};
}
@Override
protected void addConfigOptions(Map options) {
options.put(
AvailableSettings.GLOBALLY_QUOTED_IDENTIFIERS,
Boolean.TRUE
);
options.put(
AvailableSettings.HQL_BULK_ID_STRATEGY,
InlineIdsOrClauseBulkIdStrategy.class.getName()
);
}
@Before
public void setUp() {
doInJPA( this::entityManagerFactory, entityManager -> {
for ( int i = 0; i < entityCount(); i++ ) {
Doctor doctor = new Doctor();
doctor.setEmployed( ( i % 2 ) == 0 );
doctor.setEmployedOn(
Timestamp.valueOf( "2018-06-01 00:00:00" )
);
entityManager.persist( doctor );
}
for ( int i = 0; i < entityCount(); i++ ) {
Engineer engineer = new Engineer();
engineer.setEmployed( ( i % 2 ) == 0 );
engineer.setEmployedOn(
Timestamp.valueOf( "2018-06-01 00:00:00" )
);
engineer.setFellow( ( i % 2 ) == 1 );
entityManager.persist( engineer );
}
});
}
protected int entityCount() {
return 5;
}
@Test
public void testBulkUpdate() {
doInJPA( this::entityManagerFactory, entityManager -> {
int updateCount = entityManager.createQuery(
"UPDATE Person u " +
"SET u.employedOn = :date " +
"WHERE u.id IN :userIds"
)
.setParameter( "date", Timestamp.valueOf( "2018-06-03 00:00:00" ) )
.setParameter( "userIds", Arrays.asList(1L, 2L, 3L ) )
.executeUpdate();
assertEquals(3, updateCount);
});
}
@Entity(name = "Person")
@Inheritance(strategy = InheritanceType.JOINED)
public static class Person {
@Id
@GeneratedValue
private Long id;
private String name;
private boolean employed;
@Temporal( TemporalType.TIMESTAMP )
private Date employedOn;
//Getters and setters omitted for brevity
}
@Entity(name = "Doctor")
public static class Doctor extends Person {}
@Entity(name = "Engineer")
public static class Engineer extends Person {
private boolean fellow;
//Getters and setters omitted for brevity
}
}
有几个方法是从基类中重写的,例如
getAnnotatedClasses
-
它定义了我们要在这个测试用例中使用的实体类。
addConfigOptions
-
它定义了我们希望提供给Hibernate的额外配置属性。
setUp
方法使用JUnit的@Before
注解,因此它将在每次测试执行之前被调用。
testBulkUpdate
方法定义了测试逻辑,该逻辑复制了所讨论的Hibernate问题。
请注意doInJPA
方法的使用,它隐藏了创建EntityManager
、启动事务、提交事务和关闭EntityManager
的所有逻辑。
您只需要提供数据访问逻辑。
在各种RDBMS上测试
使用实际的Hibernate ORM测试套件的最佳优点之一是您可以轻松地切换底层数据库。
例如,要在PostgreSQL上运行此测试,只需从hibernate-core
文件夹运行以下Gradle命令
gradlew test --tests org.hibernate.test.bulkid.GlobalQuotedIdentifiersBulkIdTest -Pdb=pgsql
或者,如果您想直接从您的IDE运行此测试,确保使用以下命令在测试所在的Hibernate模块文件夹中设置当前数据库(例如,hibernate-core
)
gradlew sDB -Pdb=pgsql
现在,当您从您的IDE运行GlobalQuotedIdentifiersBulkIdTest
时,测试将在PostgreSQL上运行。
在
hibernate-orm/gradle/databases.gradle
配置文件中,您可以找到并自定义您可以通过Gradle的-Pdb
属性传递的数据库配置文件。
很酷的东西!
提交测试用例
现在,我们可以提交所有更改
git commit -am "HHH-12561 - bulk_id_strategy does not work with globally_quoted_identifiers"
接下来,我们需要将本地分支推送到我们的分支
git push origin HHH-12561
现在,转到您在GitHub上的hibernate-orm
分支页面,并按Compare and pull request
按钮

现在,添加一个提交信息,选择JIRA issue Test Case
标签,然后点击Click Pull Request
按钮

这就完成了!
您已经将测试用例提交给了hibernate-orm
项目,该项目可以与修复程序一起集成。
