因为所有代码(经过单元测试的产品级代码)都是从HibernateUtil获取Hibernate会话所以能在同一个位置对其进行配置为了对代码的第一位进行单元测试而访问TestSchema类将会激活静态初始化程序该程序将安装Hibernate并且将测试SessionFactory插入到HibernateUtil中对于产品级代码可以使用标准hibernatecfgxml配置机制来初始化 SessionFactory
那么单元测试中的外部特征是什么?下面的测试代码片段是用来检查逻辑的决定运动员在棒球联盟比赛中是哪个位置的人选
public void testGetEligiblePositions() throws Exception {
Player player = new Player(playerId);
TestSchemaaddPlayer(player);
FieldingStint stint = new FieldingStint
(playerId SEA PositionCATCHER);
stintsetGames();
TestSchemaaddFieldingStint(stint);
Set<Position> positions = playergetEligiblePositions();
assertEquals( positionssize());
assertTrue(ntains(PositionCATCHER));
}
第一次创建新Player实例并通过addPlayer()方法添加到TestSchema中必须首先完成此步骤因为FidldStint类和Player类之间有外键关系如果不首先添加该实例在设法添加FieldingStint时将会出现外键约束违例
一旦测试上下文就位就可以测试getEligiblePositions()方法来检索校正数据下面是在TsetSchema中addPlayer()方法的代码您将注意到使用Hibernate而不是baremetal JDBC代码
public static void addPlayer(Player player) {
if (playergetPlayerId() == null) {
throw new IllegalArgumentException(No primary key specified);
}
Session session = HibernateUtilgetSession();
Transaction transaction = sessionbeginTransaction();
try {
sessionsave(player playergetPlayerId());
mit();
}
finally {
sessionclose();
}
}
在单元测试中最重要的就是要保持测试实例是独立的因为该方法仍然涉及数据库所以需要一种方法在每个测试实例之前清理数据库在我的数据库架构中有四个表所以我在TestSchemaz上编写了reset()方法该方法从使用JDBC的表中删除所有行注意因为HSQLDB能识别外键删除表的顺序是很重要的下面是代码
public static void reset() throws SchemaException {
Session session = HibernateUtilgetSession();
try {
Connection connection = nnection();
try {
Statement statement = connectioncreateStatement();
try {
statementexecuteUpdate(delete from Batting);
statementexecuteUpdate(delete from Fielding);
statementexecuteUpdate(delete from Pitching);
statementexecuteUpdate(delete from Player);
mit();
}
finally {
statementclose();
}
}
catch (HibernateException e) {
connectionrollback();
throw new SchemaException(e);
}
catch (SQLException e) {
connectionrollback();
throw new SchemaException(e);
}
}
catch (SQLException e) {
throw new SchemaException(e);
}
finally {
sessionclose();
}
}
当确定在Hibernate 中进行大量删除操作时应该能从应用程序中删除直接JDBC的最后一位到此时为止必须获取数据库连接并向数据库直接提交SQL
在确保没有关闭连接的情况下为了释放资源只关闭会话就足够了出于手工编写许多JCBC代码来进行开发的习惯第一个版本关闭了JDBC连接因为通过配置Hibernate创建的连接池只带有一个链接在第一个之后就完全破坏了测试一定要注意这种情况!
既然在测试类运行时(设想运行所有的测试实例)不能确定数据库的状态应该在setUp()方法中包含数据库清除如下所示:
public void setUp() throws Exception {
TestSchemareset();
}
结束语
在使用像Hibernate这种复杂的O/R映射程序时必须能够测试实际存在(reallive)的RDBMS而不会发生任何针对已部署数据库的争论虽然Hibernate有内置模式生成工具让此类测试特别简单但是在这里展示的例子并不排除Hibernate并且可能与JDO或TopLink一起运行使用上面描述的设置您不必离开舒适的IDE环境但仍然可以对代码进行大量测试