如何使DataJpaTest刷新自动保存?

问题描述

我有一个带有以下列的Employee实体:

@Entity
class Employee {
  @Column(name = "first_name",length = 14)
  private String firstName;

并且我有一个Spring JPA存储库:

@Repository
public interface EmployeeRepository extends CrudRepository<Employee,Integer> {

test/resources/application.properties中,我有以下几点,以便使用内存h2数据库自动生成的表:

spring.jpa.hibernate.ddl-auto=create
spring.datasource.driver-class-name=org.h2.Driver
spring.datasource.url=jdbc:h2:mem:db;DB_CLOSE_DELAY=-1
spring.datasource.username=sa
spring.datasource.password=sa

我期望测试失败,因为firstName的时间比允许的时间长:

@DataJpaTest
public class EmployeeRepositoryTest {

  @Autowired
  private EmployeeRepository employeeRepository;

  @Test
  public void mustNotSaveFirstNameLongerThan14() {
    Employee employee = new Employee();
    employee.setFirstName("koraykoraykoray");  // 15 characters!
    employeeRepository.save(employee);
  }
}

我很惊讶地看到该测试没有失败,但是以下内容确实失败了:

@DataJpaTest
public class EmployeeRepositoryTest {

  @Autowired
  private EmployeeRepository employeeRepository;

  @Test
  public void testMustNotSaveFirstNameLongerThan14() {
    Employee employee = new Employee();
    employee.setFirstName("koraykoraykoray");  // 15 characters!
    employeeRepository.save(employee);
    employeeRepository.findAll();
  }
}

使用堆栈跟踪:

Caused by: org.h2.jdbc.JdbcsqlDataException: Value too long for column "FirsT_NAME VARCHAR(14)": "'koraykoraykoray' (15)"; sql statement:

唯一的区别是第二个测试具有附加的employeeRepository.findAll();语句,据我所知,它强制Hibernate刷新。

这对我来说并不对,我更希望save的测试立即失败。

我也可以拥有

@Autowired
private TestEntityManager testEntityManager;

并致电

testEntityManager.flush();

但是再次,这也不正确。..如何在没有任何解决方法或其他语句的情况下使该测试失败?

解决方法

这种情况下最简单的选择是配置@Transactional批注,强制将测试中的所有更改发送给数据库(只能在特定的测试中使用):

import org.springframework.transaction.annotation.Transactional;
import static org.junit.jupiter.api.Assertions.assertThrows;

@Transactional(propagation = Propagation.NOT_SUPPORTED)
@DataJpaTest
public class EmployeeRepositoryTest {

  @Autowired
  private EmployeeRepository employeeRepository;

  @Test
  public void mustNotSaveFirstNameLongerThan14() {
    Employee employee = new Employee();
    employee.setId(1);
    employee.setFirstName("koraykoraykoray");  // 15 characters!
    assertThrows(DataIntegrityViolationException.class,() -> {
        employeeRepository.save(employee);
    });
  }

  @Test
  public void mustSaveFirstNameShorterThan14() {
    Employee employee = new Employee();
    employee.setId(1);
    employee.setFirstName("koraykor");  // 8 characters!
    employeeRepository.save(employee);
  }
}

PD::由于您的存储库定义,我添加了一个简单的Integer属性作为Employee实体的PK。

您可以在下图中看到结果:

Reposity tests

,

您可以使用JpaRepository<T,ID>代替CrudRepository<T,ID>。像这样:

@Repository
public interface EmployeeRepository extends JpaRepository<Employee,Integer>

然后,您可以在需要立即发送数据的任何地方使用其saveAndFlush()方法:

@Test
public void mustNotSaveFirstNameLongerThan14() {
  Employee employee = new Employee();
  employee.setFirstName("koraykoraykoray");  // 15 characters!
  employeeRepository.saveAndFlush(employee);
}

在想要进行优化的代码中,您仍然可以使用save()方法。