如何在运行JUnit测试时告诉Hibernate不存储数据?

时间:2016-09-22 03:59:48

标签: java spring hibernate junit

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

存储库类:

@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()。是否有更好的,或更具体的,更容易实现我的意图?

3 个答案:

答案 0 :(得分:0)

创建一个接口,使用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库可以让你模拟对象,例如

答案 1 :(得分:0)

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

DAO:

@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);
    }
}

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

答案 2 :(得分:0)

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

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

可以使用 FlushMode 更改此设置。默认设置为 AUTO 。这意味着:

  

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

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

  

只有在明确显示Session.flush()时才会刷新会话   应用程序调用。

这意味着在明确调用session.flush之前,不会调用 insert 查询。如果进一步使用方法session.getsession.load,您的代码仍然有效(在当前会话中)。但是在选择 HQL查询的情况下 - 它不会找到该实体,因为它没有被持久化。所以要小心。