Hibernate和Spring测试HSQLDB
In-memory from a script: dbc:hsqldb:file:path-to-file
内存中的文件模式之间的区别是:在内存中的数据库是空的,但初始化数据文件模式。我已经在过去的战略是创建一个独立的数据库,允许Hibernate的创建表,并添加为我的数据,将数据保存到一个脚本,然后使用基于文件的URL指向的脚本。有关脚本的好处是,它是原始的SQL,所以你可以自由预先填充数据库中你要测试的任何数据。
例如,清单1显示了一个示例HSQLDB创建一个数据库,并预先填充产品,产品类别以及用户脚本。
清单1 、naturalfoods.script
CREATE SCHEMA PUBLIC AUTHORIZATION DBA
CREATE MEMORY TABLE CUSTOMER(CUSTOMER_ID BIGINT GENERATED BY DEFAULT AS IDENTITY(START WITH 1) NOT NULL
PRIMARY KEY,CUSTOMER_FIRSTNAME VARCHAR(128),CUSTOMER_LASTNAME VARCHAR(128),CUSTOMER_EMAIL
VARCHAR(128),CUSTOMER_PASSWORD VARCHAR(64))
CREATE MEMORY TABLE ADDRESS(ADDRESS_ID BIGINT GENERATED BY DEFAULT AS IDENTITY(START WITH 1) NOT NULL
PRIMARY KEY,ADDRESS_ADDRESS1 VARCHAR(255),ADDRESS_ADDRESS2 VARCHAR(255),ADDRESS_CITY
VARCHAR(255),ADDRESS_STATE VARCHAR(255),ADDRESS_ZIP VARCHAR(255),CUSTOMER_ID BIGINT NOT NULL,CONSTRAINT
FKE66327D46DF50C34 FOREIGN KEY(CUSTOMER_ID) REFERENCES CUSTOMER(CUSTOMER_ID))
CREATE MEMORY TABLE CATEGORY(CATEGORY_ID BIGINT GENERATED BY DEFAULT AS IDENTITY(START WITH 1) NOT NULL
PRIMARY KEY,CATEGORY_NAME VARCHAR(255))
CREATE MEMORY TABLE ORDER_ITEM(ORDER_ITEM_ID BIGINT GENERATED BY DEFAULT AS IDENTITY(START WITH 1) NOT NULL
PRIMARY KEY,ORDER_ITEM_QUANTITY INTEGER,ORDER_ID BIGINT NOT NULL,PRODUCT_ID BIGINT NOT NULL)
CREATE MEMORY TABLE PRODUCT(PRODUCT_ID BIGINT GENERATED BY DEFAULT AS IDENTITY(START WITH 1) NOT NULL
PRIMARY KEY,PRODUCT_NAME VARCHAR(255),PRODUCT_PRICE DOUBLE,PRODUCT_DESCRIPTION VARCHAR(255),
PRODUCT_INVENTORY INTEGER)
CREATE MEMORY TABLE PRODUCT_CATEGORIES(PRODUCT_ID BIGINT NOT NULL,CATEGORY_ID BIGINT NOT NULL,
PRIMARY KEY(PRODUCT_ID,CATEGORY_ID),CONSTRAINT FK5A93E78C121E7834 FOREIGN KEY(CATEGORY_ID)
REFERENCES CATEGORY(CATEGORY_ID),CONSTRAINT FK5A93E78CF8BBB8E0 FOREIGN KEY(PRODUCT_ID) REFERENCES
PRODUCT(PRODUCT_ID))
CREATE MEMORY TABLE ORDERS(ORDER_ID BIGINT GENERATED BY DEFAULT AS IDENTITY(START WITH 1) NOT NULL
PRIMARY KEY,ORDER_SUBTOTAL DOUBLE,ORDER_TAX DOUBLE,ORDER_TOTAL DOUBLE,CUSTOMER_ID BIGINT NOT NULL,
ADDRESS_ID BIGINT NOT NULL,CONSTRAINT FK8B7256E5AE379EC0 FOREIGN KEY(ADDRESS_ID)
REFERENCES ADDRESS(ADDRESS_ID),CONSTRAINT FK8B7256E56DF50C34 FOREIGN KEY(CUSTOMER_ID)
REFERENCES CUSTOMER(CUSTOMER_ID))
ALTER TABLE ORDER_ITEM ADD CONSTRAINT FK4BBDE984F8BBB8E0 FOREIGN KEY(PRODUCT_ID)
REFERENCES PRODUCT(PRODUCT_ID)
ALTER TABLE ORDER_ITEM ADD CONSTRAINT FK4BBDE984715B5200 FOREIGN KEY(ORDER_ID)
REFERENCES ORDERS(ORDER_ID)
ALTER TABLE CUSTOMER ALTER COLUMN CUSTOMER_ID RESTART WITH 16
ALTER TABLE ADDRESS ALTER COLUMN ADDRESS_ID RESTART WITH 1
ALTER TABLE CATEGORY ALTER COLUMN CATEGORY_ID RESTART WITH 6
ALTER TABLE ORDER_ITEM ALTER COLUMN ORDER_ITEM_ID RESTART WITH 1
ALTER TABLE PRODUCT ALTER COLUMN PRODUCT_ID RESTART WITH 7
ALTER TABLE ORDERS ALTER COLUMN ORDER_ID RESTART WITH 1
CREATE USER SA PASSWORD ""
GRANT DBA TO SA
SET WRITE_DELAY 10
SET SCHEMA PUBLIC
INSERT INTO CUSTOMER VALUES(1,'Steven','Haines','steve@javasrc.com','steve')
INSERT INTO CATEGORY VALUES(1,'Fruit')
INSERT INTO CATEGORY VALUES(2,'Vegetables')
INSERT INTO CATEGORY VALUES(3,'Meat')
INSERT INTO CATEGORY VALUES(4,'Dairy')
INSERT INTO CATEGORY VALUES(5,'Organic')
INSERT INTO PRODUCT VALUES(1,'Apple',0.25E0,'Food',10)
INSERT INTO PRODUCT VALUES(2,'Orange',0.5E0,'Food',10)
INSERT INTO PRODUCT VALUES(3,'Banana',0.75E0,'Food',0)
INSERT INTO PRODUCT VALUES(4,'Peas',1.5E0,'Food',10)
INSERT INTO PRODUCT VALUES(5,'Carrots',1.0E0,'Food',10)
INSERT INTO PRODUCT VALUES(6,'Organic Apple',0.75E0,'Food',10)
INSERT INTO PRODUCT_CATEGORIES VALUES(1,1)
INSERT INTO PRODUCT_CATEGORIES VALUES(2,1)
INSERT INTO PRODUCT_CATEGORIES VALUES(3,1)
INSERT INTO PRODUCT_CATEGORIES VALUES(4,2)
INSERT INTO PRODUCT_CATEGORIES VALUES(5,2)
INSERT INTO PRODUCT_CATEGORIES VALUES(6,1)
INSERT INTO PRODUCT_CATEGORIES VALUES(6,5)
这个脚本可能不是你想手工编写的(至少不是表的创建),但你应该简单的INSERT语句填充数据表。
在本节的例子中,我将演示如何测试一个Spring Hibernate的DAO类。如果你不熟悉Spring和Hibernate的集成,使用Spring的HibernateDaoSupport类,请参阅我的文章Spring和Hibernate Java集成参考指南。总之,Spring提供了一个非常优雅与Hibernate集成,允许你创建一个数据源,该数据源注入到会话工厂bean,并扩展HibernateDaoSupport成一个类,然后注入该会话工厂。然后,从实现的角度看,您只需致电getHibernateTemplate()并执行类似的方法你可能会发现在Hibernate的Session类,如saveOrUpdate() 、find()或delete() 。清单2显示了我的applicationContext.xml的文件,我的测试案例的内容。
清单2、applicationContext.xml中
"http://www.springframework.org/dtd/spring-beans.dtd">
我的项目有其自己的一套Spring配置文件,但我只为我的测试类创建清单2。它创建了一个数据源,使用共享连接池(DBCP)注入到SessionFactory的数据源。SessionFactory有注解的类的列表,这代表了Hibernate的领域模型,以及一组属性。hibernate.hbm2ddl.auto属性设置为“ 更新 “让Hibernate来创建和更新表,需要匹配bean,它发现在其领域模式。transactionManager的bean这是指由一个HibernateTransactionManager,被SessionFactory的创建,这是我的两个DAO类,它扩展HibernateDaoSupport注入。
清单3显示了完整的源代码,为我CustomerDaoTest的类,它测试的CustomerDao实现。
清单3、CustomerDaoTest.java package com.naturalfoods.customer.dao;
import java.util.List;
import junit.framework.Assert;
import org.apache.log4j.Logger;
import org.junit.After;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.naturalfoods.model.Customer;
public class CustomerDaoTest
{
/**
* Logger for debugging purposes
*/
private Logger logger = Logger.getLogger( CustomerDaoTest.class );
/**
* A Spring application context that we'll create from a test application context and use to create
* our DAO object (and data source, session factory, etc.)
*/
private static ApplicationContext ctx = null;
/**
* The CustomerDao that we'll be testing
*/
private CustomerDao dao;
@BeforeClass
public static void setUpBeforeClass() throws Exception
{
// Load the applicationContext.xml file
ctx = new ClassPathXmlApplicationContext( "applicationContext.xml" );
}
@Before
public void setUp()
{
dao = ( CustomerDao )ctx.getBean( "customerDao" );
}
@After
public void tearDown()
{
dao = null;
}
/**
* Tests to make sure that we can add
*/
@Test
public void testAddCustomer()
{
// Create a customer
Customer customer = new Customer();
customer.setFirstName( "Test-First" );
customer.setLastName( "Test-Last" );
customer.setEmail( "test@test.com" );
customer.setPassword( "t3st" );
// Add a customer to the database
dao.addNewCustomer( customer );
// Load the customer into another object
Customer customer2 = dao.loadCustomer( customer.getId() );
Assert.assertNotNull( "The customer that was created was unable to be loaded from the database",
customer2 );
// Assert that the customer exists
Assert.assertEquals( "First names do not match", "Test-First", customer2.getFirstName() );
Assert.assertEquals( "Last names do not match", "Test-Last", customer2.getLastName() );
Assert.assertEquals( "Email addresses do not match", "test@test.com", customer2.getEmail() );
Assert.assertEquals( "Passwords do not match", "t3st", customer2.getPassword() );
// Remove the customer from the database
dao.removeCustomer( customer2 );
// Assert that the customer is no longer in the database
Customer customer3 = dao.loadCustomer( customer.getId() );
Assert.assertNull( "The customer should have been deleted but it was not", customer3 );
System.out.println( "Customer3: " + customer3 );
}
/**
* Tests querying customers by their last name
*/
@Test
public void testQueryByLastName()
{
// Create four customers
Customer steve = new Customer( "Steven", "Haines", "steve@gomash.com", "mypass" );
Customer linda = new Customer( "Linda", "Haines", "linda@gomash.com", "mypass" );
Customer michael = new Customer( "Michael", "Haines", "michael@gomash.com", "mypass" );
Customer someone = new Customer( "Someone", "Else", "someone@somewhere.com", "notmypass" );
// Add the four customers to the database
dao.addNewCustomer( steve );
dao.addNewCustomer( linda );
dao.addNewCustomer( michael );
dao.addNewCustomer( someone );
// Query the database
List
// Assert that we found all of the records that we expected to find
Assert.assertEquals( "Did not find the three customers we inserted into the database", 3,
customers.size() );
// Debug
if( logger.isDebugEnabled() )
{
logger.debug( "All customers with a lastname of Haines:" );
for( Customer customer : customers )
{
logger.debug( "Customer: " + customer );
}
}
// Clean up
dao.removeCustomer( steve );
dao.removeCustomer( linda );
dao.removeCustomer( michael );
dao.removeCustomer( someone );
}
} applicationContext.xml的文件在CLASSPATH中,加载和加载CustomerDao bean真的只归结为两行代码:
ctx = new ClassPathXmlApplicationContext( "applicationContext.xml" );
dao = ( CustomerDao )ctx.getBean( "customerDao" );
XmlBeanFactory中的类看起来是命名的资源,在这种情况下让applicationContext.xml加载其所有的bean类。它暴露了一个方法叫做的getBean() ,它作为一个参数的bean返回给调用者。无论您是否是使用Hibernate,你可以使用这两条线路由Spring管理加载任何资源。
这个例子中的美是测试用例的代码没有做任何事情比生产代码不同:,它加载bean类和执行他们的方法。使用Hibernate作为一个内存中的数据库的所有的工作是通过定义适当的JDBC URL。
通过数据源定义使用HSQLDB的内存数据库,你的测试用例,可以运行一个新的全新数据库每次执行的时候,并没有要求你保持自己启动该数据库。此外,如果你需要在你的数据库中的数据,你可以指定一个脚本文件HSQLDB启动时使用内存中的数据库可以使用已知的数据为你写你的测试案例预先填充。总之,HSQLDB让您轻松测试你的Hibernate DAO类以外的您的应用程序,写作时颗粒状的单元测试,这是理想的情况下。