【问题标题】:How to tell Hibernate NOT to store data while running JUnit tests?如何告诉 Hibernate 在运行 JUnit 测试时不要存储数据?
【发布时间】:2017-01-30 11:57:54
【问题描述】:

我想检查我的持久性逻辑,所以我正在运行一些测试用例。

存储库类:

@Repository
public class MyRepository {
    public void add(Object obj) {
        /* Do some stuff here */
        getSession().persist(obj);
    }
}

测试类:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = { Context.class})
public class MyTests {
    @Inject
    private MyRepository myRepository;

    @Test
    @Rollback(true)
    public void foo() {
        /* Test logic */
        myRepository.add(obj);
        Assert.assert...;
    }
}

单元测试:MyTests.java 包含测试一些与持久性相关的东西的测试用例,而不是实际的 Hibernate 持久性本身,因此这就是 getSession.persist() 语句已过时的原因。

出于性能原因,我想阻止 Hibernate 将数据存储到我的数据库中,即使整个数据交互都回滚了。我的方法是模拟:getSession().persist()。有没有更好或更具体的更简单的方法来实现我的意图?

【问题讨论】:

    标签: java spring hibernate junit


    【解决方案1】:

    首先,Hibernate 中有不同的 id 生成器。如果 identity 生成器(并非所有数据库都支持),则为实体分配 id,当调用 session.persist 方法时,将调用 insert 查询。但是,例如,如果使用 sequenceuuid 生成器,则不会触发 insert(至少立即)。

    之后如果调用 session.getsession.load 方法来加载持久化(在当前会话中)对象,则不会调用 select 查询,因为它从 Hibernate 缓存中获取对象.但如果使用 HQL 选择数据,则调用 select 查询。此外,在它之前(默认情况下)insert 对持久对象的查询也会被调用。

    这可以通过 FlushMode 进行更改。默认设置为 AUTO。意思是:

    Session 有时会在查询执行之前被刷新,以便 确保查询永远不会返回陈旧状态。

    但如果设置了getSession().setHibernateFlushMode(FlushMode.MANUAL)

    只有当 Session.flush() 被显式设置时,Session 才会被刷新 由应用程序调用。

    这意味着只有在显式调用session.flush 之前,才会调用插入 查询。如果进一步使用 session.getsession.load 方法,您的代码仍然可以工作(在当前会话中)。但在 select HQL 查询的情况下 - 它不会找到实体,因为它没有被持久化。所以要小心。

    【讨论】:

      【解决方案2】:

      您需要能够模拟您的存储库对象,以便您可以在测试中使用模拟,并在应用程序的其余部分使用真实的。

      道:

      @Repository(value="MockRepo")
      public class MockMyRepositoryImpl implments MyRepository {
          @Override
          public void add(Foo foo) {
              //Do nothing here
          }
      }
      

      测试:

      @RunWith(SpringJUnit4ClassRunner.class)
      @ContextConfiguration(classes = { Context.class})
      public class MyTests {
          @Autowired
          @Qualifier("MockRepo");
          private MyRepository repo;
      
          @Test
          public void testFooSave() {
              repo.add(obj);
          }
      }
      

      另一种方法是使用另一个答案中详述的模拟框架。模拟框架更灵活,但如果你想要一些简单的东西工作,那么试试上面的。

      【讨论】:

        【解决方案3】:

        创建一个接口,使用 Hibernate persist() 方法实现它,并以这样的方式使用它:

        • 正常调用通过实现
        • 测试调用通过它的mock 版本

        public interface MyRepository {
            public void add(Object obj);
        }
        
        public class MyRepositoryImpl implements MyRepository {
            public void add(Object obj) {
                getSession().persist(obj);
            }
        }
        
        @RunWith(SpringJUnit4ClassRunner.class)
        @ContextConfiguration(classes = { Context.class})
        public class MyTests {
        
            @Mock // we inject the mock instead of the true implementation
            private MyRepository myRepository;
        
            @Test
            @Rollback(true)
            public void foo() {
                /* Test logic */
                myRepository.add(obj); // the test uses the mocked version
                Assert.assert...;
            }
        }
        

        有许多 Java 库可以让您模拟对象,例如

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2014-03-31
          • 2020-01-27
          • 2015-06-23
          • 1970-01-01
          • 2018-12-20
          • 1970-01-01
          • 2017-07-09
          • 2011-10-11
          相关资源
          最近更新 更多