Hibernate隔离集成测试

Hibernate隔离集成测试

本文介绍了Hibernate隔离集成测试的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我刚进入休眠状态,所以我从简单的事情开始.

I'm a little bit new to hibernate, so I started with simple things.

根据F.I.R.S.T测试原则,单元测试必须是I-隔离的.我正在尝试使用@Transactional批注将其应用于存储库层(Hibernate \ JPA)的集成测试:

According to F.I.R.S.T test principles, unit tests must be I - isolated.I'm trying to apply it to integration tests for repository layer (Hibernate\JPA) using @Transactional annotation:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = RepositoryConfig.class)
@Transactional
public class EmployeeRepositoryTest extends AbstractRepositoryTest {
    @Autowired
    private IEmployeeRepository employeeRepository;
    @Test
    public void saveTest() {
        Employee expectedEmployee = buildEmployee(1, "Parker");
        employeeRepository.save(expectedEmployee);
        Employee actualEmployee = employeeRepository.findById(1);
        assertEquals(expectedEmployee, actualEmployee);
    }
    private Employee buildEmployee(long id, String name) {
        Employee employee = new Employee();
        employee.setId(id);
        employee.setName(name);
        return employee;
    }
}

但是,就事务内执行两种方法而言,休眠状态实际上并不会执行(据我所知)-至少日志中没有与insert的行.

However, as far as two methods are performed within a transaction, hibernate does not actually perform them (as I understand it) - at least there's no line with insert in logs.

如果我通过向嵌入的数据源添加脚本来运行数据插入,例如:

If I run data insertion by adding a script to embeded datasourse like:

INSERT INTO employee (employee_id, employee_name) VALUES (1, 'name');

并尝试保存具有相同ID但新名称的员工,测试将成功.这对我来说是最令人困惑的事情.

and try to save employee with the same id but new name, the test will success. And that's the most confusing thing for me.

我看到了自动装配EntityManager并将其称为flush()方法的解决方案.但是我不喜欢它,因为我尝试编写测试而不与Hibernate \ JPA捆绑在一起.

I saw a solution with autowiring EntityManager and calling it's flush() method. But I don't like it, since I try to write tests without being tied to Hibernate\JPA.

我也尝试了不同的flushMode,但这也没有帮助.

I also tried different flushMode, but it didn't help either.

问题1:是否有一种方法可以在调用存储库的方法后立即使Hibernate运行查询?

Q1: Is there a way to make Hibernate run queries right after repository's method is called?

第二季度:,在保存/更新/删除存储库方法中显式调用EntityManager#flush是一种好习惯吗?

Q2: Is it a good practice to call EntityManager#flush in save/update/delete repository methods explicitly?

我的员工:

@Entity
@Table(name = "employee")
public class Employee {
    @Id
    @Column(name = "employee_id")
    private long id;
    @Column(name = "employee_name")
    private String name;
    // the rest required things (constructor, getters/setters and etc)
}

和RepositoryConfig:

and RepositoryConfig:

@Configuration
@EnableTransactionManagement
@ComponentScan("org.my.package")
public class RepositoryConfig {
    @Bean
    public DataSource getDataSource() {
        return new EmbeddedDatabaseBuilder()
                .setType(EmbeddedDatabaseType.H2)
                .build();
    }
    @Bean
    public JpaTransactionManager transactionManager() {
        return new JpaTransactionManager();
    }
    @Bean
    @Autowired
    public HibernateTemplate getHibernateTemplate(SessionFactory sessionFactory) {
        return new HibernateTemplate(sessionFactory);
    }
    @Bean
    public LocalSessionFactoryBean getSessionFactory() {
        LocalSessionFactoryBean sessionFactory = new LocalSessionFactoryBean();
        sessionFactory.setDataSource(getDataSource());
        sessionFactory.setPackagesToScan("org.my.package.model");
        sessionFactory.setHibernateProperties(getHibernateProperties());
        return sessionFactory;
    }
    private Properties getHibernateProperties() {
        Properties properties = new Properties();
        properties.put("hibernate.dialect", "H2Dialect");
        properties.put("hibernate.show_sql", true);
        return properties;
    }
}

推荐答案

您别无选择,只能与实体管理器进行交互,以使这些测试如您所愿-不会触发刷新(可以通过调用您的存储库中的saveAndFlush(..)方法,而不仅仅是save(...)),但要清除一级缓存:

You have no option but to interact with the entity manager to get these tests working as you expect - not to trigger a flush (as that can be done by calling saveAndFlush(..) method on your repository rather than just save(...)) but to clear the first level cache:

https://docs.spring.io/spring-data/jpa/docs/current/api/org/springframework/data/jpa/repository/JpaRepository.html#saveAndFlush-S-

@Test
public void saveTest() {
    Employee expectedEmployee = buildEmployee(1, "Parker");

    //call save and flush for immediate flush.
    employeeRepository.saveAndFlush(expectedEmployee);

    //now you will need to clear the persistence context to actually
    //trigger a load from the database as employee with id 1 is already
    //in the persistence context.

    //without the below you will not see a db select
    entityManager.clear();

    Employee actualEmployee = employeeRepository.findById(1);
    assertEquals(expectedEmployee, actualEmployee);
}

清除持久性上下文的另一种方法是使用原始JDBC来读取更新的行.

An alternative to clearing the persistence context is to fall back to using raw JDBC to read the updated row(s).

但是我不喜欢它,因为我尝试编写不受Hibernate \ JPA束缚的测试.您正在测试在Hibernate \ JPA中实现的持久性机制,并且您的存储库只是一个抽象这样可以避免直接调用它,所以这似乎有点荒谬.

But I don't like it, since I try to write tests without being tied to Hibernate\JPA. You are testing a persistence mechanism implemented in Hibernate\JPA and your repository is just an abstraction that is allowing you to avoid direct calls to it so this seems a slightly ridiculous statement.

这篇关于Hibernate隔离集成测试的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

07-25 12:41