hibernate sessionFactory.getCurrentSession()。flush()不适用于测试

时间:2016-09-29 09:54:08

标签: java spring hibernate testng

我使用以下技术:

  • TestNG的(6.9.10)
  • 弹簧(4.3.2.RELEASE)
  • 休眠(5.1.0.Final)
  • Java 8

我通过集成测试测试了一些具有功能的代码,我需要检查实体是否正确保存/更新/删除或任何其他更改。我的 .xml 中有 sessionFactory 配置:

<bean id="sessionFactory" class="org.springframework.orm.hibernate5.LocalSessionFactoryBean"
      p:dataSource-ref="dataSource" p:hibernateProperties="jdbcProperties">
    <property name="packagesToScan" value="my.package"/>
</bean>

和测试类示例:

@ContextConfiguration(locations = {"classpath:/applicationContext-test.xml",
    "classpath:/applicationContext-dao.xml",
    "classpath:/applicationContext-orm.xml"})
public class AccountServiceTest extends AbstractTransactionalTestNGSpringContextTests {

@Autowired
private SomeService someService;
@Autowired
private SessionFactory sessionFactory;

@Test
public void updateEntity() {
    //given
    Long entityId = 1L;
    SomeClass expected = someService.get(entityId);
    String newPropertyValue = "new value";
    //when
    someService.changeEntity(entity, newPropertyValue);
    // Manual flush is required to avoid false positive in test
    sessionFactory.getCurrentSession().flush();
    //then
    expected = someService.get(entityId);
    Assert.assertEquals(expected.getChangedProperty() , newPropertyValue);
}

服务方式:

@Transactional
@Override
public int changeEntity(entity, newPropertyValue) {
    return dao().executeNamedQuery(REFRESH_ACCESS_TIME_QUERY,
            CollectionUtils.arrayToMap("id", entity.getId(), "myColumn", newPropertyValue));
}

DAO:

@Override
public int executeNamedQuery(final String query, final Map<String, Object> parameters) {
    Query queryObject = sessionFactory.getCurrentSession().getNamedQuery(query);
    if (parameters != null) {
        for (Map.Entry<String, Object> entry : parameters.entrySet()) {
            NamedQueryUtils.applyNamedParameterToQuery(queryObject, entry.getKey(), entry.getValue());
        }
    }
    return queryObject.executeUpdate();
}

但是我的实体属性在flush()

之后没有改变

如此处所述change @Autowire SessionFactory with @PersistenceContext EntityManager ,我应该EntityManager使用flush() - 但我不能这样做 - 我无法将sessionFactory转换为{{1}我不需要为我的应用程序创建EntityManager - 因为我需要更改 .xml 配置文件和其他文件。

这个问题还有其他解决办法吗?

1 个答案:

答案 0 :(得分:0)

您的代码实际上正在按预期工作。

您的测试方法是事务性的,因此在整个测试方法执行期间Session仍然存在。 Session也是hibernate的第一级缓存,当从数据库加载实体时,它被放入会话中。

因此,行SomeClass expected = someService.get(entityId);将从数据库加载实体,并将其放入Session

现在这行expected = someService.get(entityId);首先检查(实际上是下面的dao方法)检查​​具有id的请求类型的实体是否已经存在于Session中,如果是这样,它只是返回它。它将查询数据库!。

主要问题是你以错误的方式使用hibernate,你基本上是以更新数据库的方式绕过hibernate。您应该更新您的实体并坚持下去。您不应该编写查询来更新数据库!

带注释的测试方法

@Test
public void updateEntity() {
    //given
    Long entityId = 1L;
    SomeClass expected = someService.get(entityId); // load from db and put in Sesion
    String newPropertyValue = "new value";
    //when
    someService.changeEntity(entity, newPropertyValue); // update directly in database bypass Session and entity
    // Manual flush is required to avoid false positive in test
    sessionFactory.getCurrentSession().flush();
    //then
    expected = someService.get(entityId); // return entity from Session
    Assert.assertEquals(expected.getChangedProperty() , newPropertyValue);
}

要仅修复测试,请在clear()之后添加对flush()的调用。

sessionFactory.getCurrentSession().clear();

然而,您实际应该做的是停止编写这样的代码并以正确的方式使用Hibernate和持久实体。

@Test
public void updateEntity() {
    //given
    Long entityId = 1L;
    String newPropertyValue = "new value";

    SomeClass expected = someService.get(entityId); 
    expected.setMyColumn(newPropertyValue);

    //when
    someService.changeEntity(entity); 

    sessionFactory.getCurrentSession().flush();

    // now you should use a SQL query to verify the state in the DB. 
    Map<String, Object> dbValues = getJdbcTemplate().queryForMap("select * from someClass where id=?", entityId);
    //then
    Assert.assertEquals(dbValues.get("myColumn"), newPropertyValue);
}

你的dao方法应该是这样的。

public void changeEntity(SomeClass entity) {
    sessionFactory.getCurrentSession().saveOrUpdate(entity);
}