如何测试JPA保存实际上是否保存数据?

时间:2014-10-07 21:51:54

标签: spring unit-testing jpa

我在Spring中使用JPA并在测试中保存实体。在编写测试以验证实体与另一个实体的关系是否正确设置的过程中,我遇到了一个我经常遇到的问题。我有一个测试方法(设置为回滚):

  1. 创建实体
  2. 保存实体
  3. 刷新
  4. 检索实体
  5. 验证实体
  6. 问题在于,当我查看Hibernate日志时,我只看到数据库的单个插入,我希望看到插入然后选择。

    我知道这是因为Hibernate试图节省我一些时间,并且知道它有一个带有ID的实体我试图检索但是绕过了一个重要的步骤:我想要确保实体实际上使它成为数据库并且看起来像我认为的那样。什么是解决这个问题的最佳方法,以便我可以测试该实体实际上是在数据库中?

    注意:我认为这涉及以某种方式分离实体或告诉Hibernate清除其缓存但我不确定当我有权访问的是JpaRepository对象时如何做到这一点。

    一些代码:

    public interface UserRepository extends JpaRepository<User, Long> {
        //...
    }
    
    @RunWith(SpringJUnit4ClassRunner.class)
    @ContextConfiguration(classes = JpaConfig.class, // JpaConfig just loads our config stuff
        loader = AnnotationConfigContextLoader.class)
    @TransactionConfiguration(defaultRollback = true)
    public class UserRepositoryTest {
        @Test
        @Transactional
        public void testRoles() {
            User user = new User("name", "email@email.com");
    
            // eventually more here to test entity-to-entity relationship
    
            User savedUser = userRepository.save(user);
            userRepository.flush();
    
            savedUser = userRepository.findOne(savedUser.getId());
    
            Assert.assertNotNull(savedUser);
            // more validation here
        }
    
    }
    

2 个答案:

答案 0 :(得分:1)

您基本上想要测试Hibernate的功能而不是您自己的代码。我的第一个建议是:不要这样做!它已经过多次测试和验证。

如果你真的想测试它,有几个选择:

  1. 执行一个查询(而不是一个get。查询将被执行(你应该在日志中看到它)并解释结果。你得到的对象仍然是你保存的对象,因为它在会话。
  2. 您可以从会话中逐出该对象,然后再次获取该对象。如果您使用SessionFactory.getCurrentSession(),您将获得与存储库使用的季节相同的季节。这样你就可以驱逐对象。

答案 1 :(得分:1)

您有两种策略:

  1. 为此绕过任何JPA缓存发出本机SQL查询。
  2. 确保在重新加载之前清除持久性上下文。
  3. 对于(1),您可以更改测试以扩展以下Spring类,除了在每个测试的开始/结束时自动开始/回滚事务之外,还将允许您访问可以使用的Spring JdbcTemplate发出本机SQL。

    http://docs.spring.io/spring-framework/docs/2.5.6/api/org/springframework/test/context/junit4/AbstractTransactionalJUnit4SpringContextTests.html

    http://docs.spring.io/spring-framework/docs/2.5.6/api/org/springframework/jdbc/core/simple/SimpleJdbcTemplate.html

    对于(2),您可以通过执行以下操作来清除持久性上下文(将EntityManagerFactory注入到您的测试中:

    EntityManagerFactoryUtils.getTransactionalEntityManager(entityManagerFactory).clear();
    

    请参阅我通常使用的以下基本测试类并演示上述内容,并允许在每次测试之前使用已知数据填充数据库(通过DBUnit)。

    https://github.com/alanhay/spring-data-jpa-bootstrap/blob/master/src/test/java/uk/co/certait/spring/data/repository/AbstractBaseDatabaseTest.java

    (事实上在上面我实际上是通过注入一个数据源创建一个新的JdbcTemplate。不记得为什么......)