Hibernate изолированные интеграционные тесты - PullRequest
0 голосов
/ 04 декабря 2018

Я немного новичок в спящем режиме, поэтому я начал с простых вещей.

Согласно принципам FIRST, модульные тесты должны быть I-изолированными.Я пытаюсь применить его к интеграционным тестам для уровня репозитория (Hibernate \ JPA) с использованием аннотации @Transactional:

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

Однако, поскольку в транзакции выполняются два метода, hibernate на самом деле не работает.выполнить их (как я понимаю) - по крайней мере в логах нет строки с insert .

Если я запусту вставку данных, добавив скрипт к встраиваемому источнику данных, например:

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

, и попытаюсь сохранить сотрудника с тем же идентификатором, но с новым именем, проверка пройдет успешно.И это самое запутанное для меня.

Я видел решение с автопроводкой EntityManager и вызовом этого метода flush().Но мне это не нравится, поскольку я пытаюсь писать тесты, не привязываясь к Hibernate \ JPA.

Я также пробовал разные flushMode, но это тоже не помогло.

Q1: Есть ли способ заставить Hibernate запускать запросы сразу после вызова метода репозитория?

Q2: Полезно ли вызывать EntityManager#flush при сохранении/ обновить / удалить методы репозитория явно?

Мой сотрудник:

@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:

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

1 Ответ

0 голосов
/ 05 декабря 2018

У вас нет выбора, кроме как взаимодействовать с менеджером сущностей, чтобы эти тесты работали так, как вы ожидаете, - чтобы не вызывать сброс (как это можно сделать, вызвав метод saveAndFlush(..) в вашем хранилище, а не просто save(...))но чтобы очистить кэш первого уровня:

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 для чтения обновленных строк.

Но мне это не нравится, поскольку я пытаюсь писать тесты, не привязываясь к Hibernate \ JPA. Вы тестируете механизм персистентности, реализованный в Hibernate \ JPA, и ваш репозиторий простоабстракция, которая позволяет вам избегать прямых обращений к ней, так что это выглядит немного нелепо.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...