Java 如何使用Hibernate、H2和TestNg进行测试?
测试DAO层的正确方法是什么 我有Java 如何使用Hibernate、H2和TestNg进行测试?,java,hibernate,testing,integration-testing,testng,Java,Hibernate,Testing,Integration Testing,Testng,测试DAO层的正确方法是什么 我有@beforethod和@AfterMethod带注释的方法,在这些方法中我创建并销毁了SessionFactory,但它不能用于多个测试。如果一个接一个地运行测试,那么测试是通过的,但是在一起运行时,maven构建没有通过,所以我决定使用TestNg组对它们进行分组,并使用@BeforeGroup和@AfterGroup方法,我在Hibernate中也做了同样的事情 所以我做了这样的事情: @Test(groups = {"integration"}) pub
@beforethod
和@AfterMethod
带注释的方法,在这些方法中我创建并销毁了SessionFactory
,但它不能用于多个测试。如果一个接一个地运行测试,那么测试是通过的,但是在一起运行时,maven构建没有通过,所以我决定使用TestNg组对它们进行分组,并使用@BeforeGroup
和@AfterGroup
方法,我在Hibernate中也做了同样的事情
所以我做了这样的事情:
@Test(groups = {"integration"})
public class IntegrationTest
{
protected SessionFactory sessionFactory;
@BeforeGroups(groups = {"integration"})
public void setUpHibernate() throws Exception
{
// here I configure sessionFactory
this.sessionFactory = ...
}
@AfterGroups(groups = {"integration"})
public void putItDown() throws Exception
{
sessionFactory.close();
}
}
我的每一次测试都像这样扩展了这个类
@Test(groups = "integration")
public class RateRepositoryHibernateTest extends IntegrationTest
{
...
}
然后我注意到只有一个扩展测试设置了sessionFactory
,其余测试设置为null
,这并不奇怪,因为该方法应该运行一次。现在我真的不知道该怎么办
如何围绕组测试方法传递来自BeforeGroup方法的数据
或
如何做得不同
或
如何在每次测试之前和之后设置和拆卸SessionFactory
,但在多个测试中不会出现任何伪锁异常
--
编辑:
回答解释如何以不同的方式进行也是受欢迎的。我想知道使用TestNg、Hibernate和一些内存数据库进行集成测试的最新技术
--
编辑2:
堆栈跟踪,下面是测试代码
Hibernate: select roomtype_.type_name from ROOM_TYPES roomtype_ where roomtype_.type_name=?
Hibernate: call next value for rates_sequence
Hibernate: call next value for rates_sequence
Hibernate: insert into ROOMS (prefix, housekeepingStatus, availability, maxExtraBeds, standard, maximum, type, name) values (?, ?, ?, ?, ?, ?, ?, ?)
Hibernate: insert into RATES (standardPrice, upchargeExtraPerson, upchargeExtraBed, room, RATE_TYPE, id) values (?, ?, ?, ?, 'R', ?)
Hibernate: insert into RATES (standardPrice, upchargeExtraPerson, upchargeExtraBed, room, seasonId, RATE_TYPE, id) values (?, ?, ?, ?, ?, 'S', ?)
Hibernate: insert into ROOM_TYPES (type_name) values (?)
Hibernate: select roomtype_.type_name from ROOM_TYPES roomtype_ where roomtype_.type_name=?
Hibernate: call next value for rates_sequence
Hibernate: insert into ROOMS (prefix, housekeepingStatus, availability, maxExtraBeds, standard, maximum, type, name) values (?, ?, ?, ?, ?, ?, ?, ?)
Hibernate: insert into RATES (standardPrice, upchargeExtraPerson, upchargeExtraBed, room, RATE_TYPE, id) values (?, ?, ?, ?, 'R', ?)
org.hibernate.PessimisticLockException: Timeout trying to lock table ; SQL statement:
insert into RATES (standardPrice, upchargeExtraPerson, upchargeExtraBed, room, RATE_TYPE, id) values (?, ?, ?, ?, 'R', ?) [50200-168]
at org.hibernate.dialect.H2Dialect$2.convert(H2Dialect.java:317)
at org.hibernate.exception.internal.StandardSQLExceptionConverter.convert(StandardSQLExceptionConverter.java:49)
at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:125)
at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:110)
at org.hibernate.engine.jdbc.internal.proxy.AbstractStatementProxyHandler.continueInvocation(AbstractStatementProxyHandler.java:129)
at org.hibernate.engine.jdbc.internal.proxy.AbstractProxyHandler.invoke(AbstractProxyHandler.java:81)
at $Proxy13.executeUpdate(Unknown Source)
at org.hibernate.engine.jdbc.batch.internal.NonBatchingBatch.addToBatch(NonBatchingBatch.java:56)
at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:2962)
at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:3403)
at org.hibernate.action.internal.EntityInsertAction.execute(EntityInsertAction.java:88)
at org.hibernate.engine.spi.ActionQueue.execute(ActionQueue.java:362)
at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:354)
at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:275)
at org.hibernate.event.internal.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:326)
at org.hibernate.event.internal.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:52)
at org.hibernate.internal.SessionImpl.flush(SessionImpl.java:1210)
at org.hibernate.internal.SessionImpl.managedFlush(SessionImpl.java:399)
at org.hibernate.engine.transaction.internal.jdbc.JdbcTransaction.beforeTransactionCommit(JdbcTransaction.java:101)
at org.hibernate.engine.transaction.spi.AbstractTransactionImpl.commit(AbstractTransactionImpl.java:175)
at net.mklew.hotelms.persistance.RatesPersistanceTest.should_save_rates_and_retrieve_them_with_success(RatesPersistanceTest.java:80)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:601)
at org.testng.internal.MethodInvocationHelper.invokeMethod(MethodInvocationHelper.java:80)
at org.testng.internal.Invoker.invokeMethod(Invoker.java:673)
at org.testng.internal.Invoker.invokeTestMethod(Invoker.java:842)
at org.testng.internal.Invoker.invokeTestMethods(Invoker.java:1166)
at org.testng.internal.TestMethodWorker.invokeTestMethods(TestMethodWorker.java:125)
at org.testng.internal.TestMethodWorker.run(TestMethodWorker.java:109)
at org.testng.TestRunner.runWorkers(TestRunner.java:1178)
at org.testng.TestRunner.privateRun(TestRunner.java:757)
at org.testng.TestRunner.run(TestRunner.java:608)
at org.testng.SuiteRunner.runTest(SuiteRunner.java:334)
at org.testng.SuiteRunner.runSequentially(SuiteRunner.java:329)
at org.testng.SuiteRunner.privateRun(SuiteRunner.java:291)
at org.testng.SuiteRunner.run(SuiteRunner.java:240)
at org.testng.SuiteRunnerWorker.runSuite(SuiteRunnerWorker.java:52)
at org.testng.SuiteRunnerWorker.run(SuiteRunnerWorker.java:86)
at org.testng.TestNG.runSuitesSequentially(TestNG.java:1158)
at org.testng.TestNG.runSuitesLocally(TestNG.java:1083)
at org.testng.TestNG.run(TestNG.java:999)
at org.testng.remote.RemoteTestNG.run(RemoteTestNG.java:111)
at org.testng.remote.RemoteTestNG.initAndRun(RemoteTestNG.java:203)
at org.testng.remote.RemoteTestNG.main(RemoteTestNG.java:174)
at org.testng.RemoteTestNGStarter.main(RemoteTestNGStarter.java:111)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:601)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:120)
Caused by: org.h2.jdbc.JdbcSQLException: Timeout trying to lock table ; SQL statement:
insert into RATES (standardPrice, upchargeExtraPerson, upchargeExtraBed, room, RATE_TYPE, id) values (?, ?, ?, ?, 'R', ?) [50200-168]
at org.h2.message.DbException.getJdbcSQLException(DbException.java:329)
at org.h2.message.DbException.get(DbException.java:158)
at org.h2.command.Command.filterConcurrentUpdate(Command.java:276)
at org.h2.command.Command.executeUpdate(Command.java:232)
at org.h2.jdbc.JdbcPreparedStatement.executeUpdateInternal(JdbcPreparedStatement.java:156)
at org.h2.jdbc.JdbcPreparedStatement.executeUpdate(JdbcPreparedStatement.java:142)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:601)
at org.hibernate.engine.jdbc.internal.proxy.AbstractStatementProxyHandler.continueInvocation(AbstractStatementProxyHandler.java:122)
... 47 more
Caused by: org.h2.jdbc.JdbcSQLException: Concurrent update in table "PRIMARY_KEY_4": another transaction has updated or deleted the same row [90131-168]
at org.h2.message.DbException.getJdbcSQLException(DbException.java:329)
at org.h2.message.DbException.get(DbException.java:169)
at org.h2.message.DbException.get(DbException.java:146)
at org.h2.table.RegularTable.addRow(RegularTable.java:146)
at org.h2.command.dml.Insert.insertRows(Insert.java:124)
at org.h2.command.dml.Insert.update(Insert.java:84)
at org.h2.command.CommandContainer.update(CommandContainer.java:75)
at org.h2.command.Command.executeUpdate(Command.java:230)
... 54 more
测试代码:
public class RatesPersistanceTest
{
protected SessionFactory sessionFactory;
protected HibernateSessionFactory hibernateSessionFactory;
@BeforeMethod
public void setUpHibernate() throws Exception
{
Logger logger = mock(Logger.class);
NativelyConfiguredHibernateSessionFactory hibernateSessionFactory = new
NativelyConfiguredHibernateSessionFactory(logger);
this.sessionFactory = hibernateSessionFactory.getSessionFactory();
this.hibernateSessionFactory = hibernateSessionFactory;
}
@AfterMethod
public void putItDown() throws Exception
{
sessionFactory.close();
}
@Test
public void should_save_rates_and_retrieve_them_with_success()
{
// given
Money standardPrice = Money.parse("USD 85");
Money upchargeExtraPerson = Money.parse("USD 80");
Money upchargeExtraBed = Money.parse("USD 75");
RoomType roomType = getMeRoomType();
Room room = getMeRoom(roomType);
AvailabilityPeriod availabilityPeriod = new AvailabilityPeriod(DateTime.now(), DateTime.now().plusDays(5),
true);
Season season = new BasicSeason("season name", availabilityPeriod);
Rate seasonRate = new SeasonRate(standardPrice, upchargeExtraPerson, upchargeExtraBed, room, season);
Session session = sessionFactory.openSession();
session.beginTransaction();
session.save(roomType);
// session.save(room);
session.getTransaction().commit();
session.close();
session = sessionFactory.openSession();
session.beginTransaction();
// session.save(roomType);
session.save(room);
session.getTransaction().commit();
session.close();
session = sessionFactory.openSession();
session.beginTransaction();
session.save(season);
session.save(seasonRate);
session.getTransaction().commit();
session.close();
// when
session = sessionFactory.openSession();
session.beginTransaction();
final List<Rate> list = session.createQuery("from Rate").list();
// then
assertThat(list).contains(seasonRate);
session.getTransaction().commit();
session.close();
}
@Test( expectedExceptions = org.hibernate.exception.ConstraintViolationException.class)
public void season_rate_should_violate_db_constraints_when_saved_without_season()
{
// given
Money standardPrice = Money.parse("USD 85");
Money upchargeExtraPerson = Money.parse("USD 80");
Money upchargeExtraBed = Money.parse("USD 75");
RoomType roomType = getMeRoomType();
final RoomName roomName = new RoomName("103");
final Money roomStandardPrice = Money.parse("USD 100");
final Money roomUpchargeExtraPerson = Money.parse("USD 50");
final Money roomUpchargeExtraBed = Money.parse("USD 20");
final RackRate rackRate = new RackRate(roomStandardPrice, roomUpchargeExtraPerson, roomUpchargeExtraBed, null);
final int maxExtraBeds = 2;
final Occupancy occupancy = new Occupancy(4, 2);
Room room = new Room("C", roomName, roomType, HousekeepingStatus.CLEAN, RoomAvailability.AVAILABLE,
maxExtraBeds, occupancy, standardPrice, upchargeExtraPerson, upchargeExtraBed);
AvailabilityPeriod availabilityPeriod = new AvailabilityPeriod(DateTime.now(), DateTime.now().plusDays(5),
true);
Season season = new BasicSeason("season name", availabilityPeriod);
Rate seasonRate = new SeasonRate(standardPrice, upchargeExtraPerson, upchargeExtraBed, room, null);
Session session = sessionFactory.openSession();
session.beginTransaction();
session.save(room);
// when
session.save(seasonRate);
session.getTransaction().commit();
session.close();
// then exception should be thrown
}
// @Test
// public void package_rate_should_violate_db_constraints_when_saved_without_package()
// {
//
// }
private RoomType getMeRoomType()
{
final RoomType roomType = new RoomType("cheap" + DateTime.now().toString());
return roomType;
}
private Room getMeRoom(RoomType roomType)
{
final RoomName roomName = new RoomName("101001" + DateTime.now().toString());
final Money standardPrice = Money.parse("USD 100");
final Money upchargeExtraPerson = Money.parse("USD 50");
final Money upchargeExtraBed = Money.parse("USD 20");
final RackRate rackRate = new RackRate(standardPrice, upchargeExtraPerson, upchargeExtraBed, null);
final int maxExtraBeds = 2;
final Occupancy occupancy = new Occupancy(4, 2);
return new Room("C", roomName, roomType, HousekeepingStatus.CLEAN, RoomAvailability.AVAILABLE, maxExtraBeds,
occupancy, standardPrice, upchargeExtraPerson, upchargeExtraBed);
}
}
public class RatesPersistanceTest
{
受保护的SessionFactory SessionFactory;
受保护的HibernateSessionFactory HibernateSessionFactory;
@预处理法
public void setUpHibernate()引发异常
{
Logger=mock(Logger.class);
NativelyConfiguredHibernateSessionFactory hibernateSessionFactory=新建
本地配置的HibernateSessionFactory(记录器);
this.sessionFactory=hibernateSessionFactory.getSessionFactory();
this.hibernateSessionFactory=hibernateSessionFactory;
}
@后置法
public void putItDown()引发异常
{
sessionFactory.close();
}
@试验
public void应保存费率并通过成功检索费率()
{
//给定
货币标准价格=货币解析(“85美元”);
Money upchargeExtraPerson=Money.parse(“80美元”);
货币加价附加=货币解析(“75美元”);
RoomType RoomType=getMeRoomType();
房间=getMeRoom(房间类型);
AvailabilityPeriod AvailabilityPeriod=新的AvailabilityPeriod(DateTime.now(),DateTime.now()。plusDays(5),
正确的);
季节=新的基本季节(“季节名称”,availabilityPeriod);
费率季节费率=新的季节费率(标准价格、额外收费人员、额外收费床、房间、季节);
Session Session=sessionFactory.openSession();
session.beginTransaction();
session.save(roomType);
//保存(房间);
session.getTransaction().commit();
session.close();
session=sessionFactory.openSession();
session.beginTransaction();
//session.save(roomType);
保存(房间);
session.getTransaction().commit();
session.close();
session=sessionFactory.openSession();
session.beginTransaction();
保存(季节);
保存(季节性费率);
session.getTransaction().commit();
session.close();
//什么时候
session=sessionFactory.openSession();
session.beginTransaction();
最终列表=session.createQuery(“从速率”).List();
//然后
资产(清单)。包含(价格);
session.getTransaction().commit();
session.close();
}
@测试(expectedExceptions=org.hibernate.exception.ConstraintViolationException.class)
公共无效季节率在没有季节的情况下保存时应违反db约束
{
//给定
货币标准价格=货币解析(“85美元”);
Money upchargeExtraPerson=Money.parse(“80美元”);
货币加价附加=货币解析(“75美元”);
RoomType RoomType=getMeRoomType();
最终RoomName RoomName=新RoomName(“103”);
最终货币标准价格=货币解析(“100美元”);
最终货币roomUpchargeExtraPerson=Money.parse(“50美元”);
最终货币roomUpchargeExtraBed=Money.parse(“20美元”);
最终RackRate RackRate=新RackRate(roomStandardPrice,roomUpchargeExtraPerson,roomUpchargeExtraBed,null);
最终int maxExtraBeds=2;
最终入住率=新入住率(4,2);
Room Room=新房间(“C”,房间名称,房间类型,客房管理状态。清洁,RoomAvailability.AVAILABLE,
MaxExtrabed、入住率、标准价格、加价Extraped、加价Extrabed);
AvailabilityPeriod AvailabilityPeriod=新的AvailabilityPeriod(DateTime.now(),DateTime.now()。plusDays(5),
正确的);
季节=新的基本季节(“季节名称”,availabilityPeriod);
费率季节费率=新的季节费率(标准价格、加价加人、加价加床、房间、空);
Session Session=sessionFactory.openSession();
session.beginTransaction();
保存(房间);
//什么时候
保存(季节性费率);
session.getTransaction().commit();
session.close();
//然后应该抛出异常
}
//@测试
//公共无效包\u比率\u在没有\u包()的情况下保存\u时应\u违反\u db\u约束\u
// {
//
// }
private RoomType getMeRoomType()
{
final-RoomType-RoomType=new-RoomType(“便宜”+DateTime.now().toString());
返回房间类型;
}
私人房间getMeRoom(RoomType RoomType)
{
final RoomName RoomName=新RoomName(“101001”+DateTime.now().toString());
最终货币标准价格=货币解析(“100美元”);
最终支付的费用个人=货币
<hibernate-configuration>
<session-factory>
<!-- Database connection settings -->
<property name="connection.driver_class">org.h2.Driver</property>
<property name="connection.url">jdbc:h2:mem:db1;DB_CLOSE_DELAY=0;MVCC=true</property>
<property name="connection.username">sa</property>
<property name="connection.password"/>
<!-- JDBC connection pool (use the built-in) -->
<property name="connection.pool_size">1</property>
<!-- SQL dialect -->
<property name="dialect">org.hibernate.dialect.H2Dialect</property>
<!-- Disable the second-level cache -->
<property name="cache.provider_class">org.hibernate.cache.internal.NoCachingRegionFactory</property>
<!-- Enable Hibernate's automatic session context management -->
<property name="current_session_context_class">thread</property>
<!-- Echo all executed SQL to stdout -->
<property name="show_sql">true</property>
<!-- Drop and re-create the database schema on startup -->
<property name="hbm2ddl.auto">create-drop</property>
<!-- skipped mappings -->
</session-factory>
</hibernate-configuration>
@ContextConfiguration(locations = { "file:src/test/resources/test-context.xml" })
@TransactionConfiguration(defaultRollback = true)
public class TheDAOTest extends AbstractTestNGSpringContextTests {
private static final Logger LOG = Logger.getLogger(TheDAOTest.class);
// N.B. this will be wired AFTER @BeforeTest !!
@Autowired TheDAO subject;
@BeforeMethod
public void beforeMethod() {
final HibernateTemplate ht = subject.getHibernateTemplate();
ht.deleteAll(subject.listCustomers());
}
@Test
public void noCustomers() {
final List<CustomerDTO> customers = subject.listCustomers();
assert customers != null : "listCustomers null result";
LOG.info("listCustomers: " + customers);
assert customers.size() == 0 : "Expected zero customers";
final CustomerDTO customer = subject.findCustomerById(0L);
assert customer == null : "Unexpected customer found";
}
@Test
public void saveAndFind() {
final CustomerDTO dto1 = makeDTO("0");
final CustomerDTO saved = subject.save(dto1);
assert saved != null ;
final Long id1 = saved.getId();
CustomerDTO customer = subject.findCustomerById(id1);
assert customer != null ;
assert customer.getId().equals(id1);
assert customer.getTN().equals(dto1.getTN());
List<CustomerDTO> customers = subject.listCustomers();
assert customers != null : "listCustomers null result";
LOG.info("saveAndFind - listCustomers: " + customers);
assert customers.size() == 1 : "Expected one customer";
subject.save(makeDTO("1"));
customer = subject.findCustomerById(id1);
assert customer != null ;
assert customer.getId().equals(id1);
customers = subject.listCustomers();
assert customers != null : "listCustomers null result";
LOG.info("saveAndFind - listCustomers: " + customers);
assert customers.size() == 2 : "Expected two customers";
}
private CustomerDTO makeDTO(final String x) {
final CustomerDTO dto = new CustomerDTO();
dto.setX(x);
return dto;
}
}
@Entity @Table(name = "customers") public class CustomerDTO {
@Id @GeneratedValue(strategy = GenerationType.AUTO) private Long id = Long.MIN_VALUE;
@Column private String X;
public Long getId() {
return id;
}
public void setId(final Long id) {
this.id = id;
}
public String getX() {
return this.X;
}
public void setX(final String x) {
this.X = x;
}
// etc.
}
@Component
public class TheDAO {
public List<CustomerDTO> listCustomers() {
return getHibernateTemplate().loadAll(CustomerDTO.class);
}
public CustomerDTO getCustomer(final Long id) {
return getHibernateTemplate().get(CustomerDTO.class, id);
}
public List<CustomerDTO> listCustomers() {
return getHibernateTemplate().loadAll(CustomerDTO.class);
}
public <T> T save(final T valueObject) {
getHibernateTemplate().saveOrUpdate(valueObject);
return valueObject;
}
public void setHibernateTemplate(final HibernateTemplate hibernateTemplate) {
TheDAO.hibernateTemplate = hibernateTemplate;
}
CustomerDTO findCustomerById(final Long id) {
return getHibernateTemplate().get(CustomerDTO.class, id);
}
HibernateTemplate getHibernateTemplate() {
return TheDAO.hibernateTemplate;
}
}
@Override
protected void setUp() throws Exception {
super.setUp();
String dialectClassName = HSQLDialect.class.getName();
AnnotationConfiguration config = new AnnotationConfiguration().addAnnotatedClass(DividendScheduleGeneratorImpl.class);
config.setProperty(Environment.DIALECT, dialectClassName);
config.setProperty(Environment.DRIVER, jdbcDriver.class.getName());
config.setProperty(Environment.URL, "jdbc:hsqldb:mem:testDB");
config.setProperty(Environment.USER, "SA");
config.setProperty(Environment.PASS, "");
SchemaExport export = new SchemaExport(config);
export.create(false, true);
sessions = config.buildSessionFactory();
}
@Override
protected void tearDown() throws Exception {
sessions.close();
sessions = null;
super.tearDown();
}
jdbc:h2:mem:db1;DB_CLOSE_DELAY=0;MVCC=true
jdbc:h2:mem:<TESTNAME>;DB_CLOSE_DELAY=0;MVCC=true
@Test(singleThreaded=true)
public class RatesPersistanceTest