Kor*_*gay 9 spring hibernate spring-data-jpa
我有一个Employee
具有以下列的实体:
@Entity
class Employee {
@Column(name = "first_name", length = 14)
private String firstName;
Run Code Online (Sandbox Code Playgroud)
我有一个 Spring JPA 存储库:
@Repository
public interface EmployeeRepository extends CrudRepository<Employee, Integer> {
Run Code Online (Sandbox Code Playgroud)
我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
Run Code Online (Sandbox Code Playgroud)
我预计这个测试会失败,因为它的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);
}
}
Run Code Online (Sandbox Code Playgroud)
我很惊讶地发现这个测试没有失败,但是以下测试确实失败了:
@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();
}
}
Run Code Online (Sandbox Code Playgroud)
与堆栈跟踪:
Caused by: org.h2.jdbc.JdbcSQLDataException: Value too long for column "FIRST_NAME VARCHAR(14)": "'koraykoraykoray' (15)"; SQL statement:
Run Code Online (Sandbox Code Playgroud)
唯一的区别是第二个测试有附加employeeRepository.findAll();
语句,据我所知,这会强制 Hibernate 刷新。
这对我来说感觉不对,我宁愿希望测试立即失败save
。
我也可以有
@Autowired
private TestEntityManager testEntityManager;
Run Code Online (Sandbox Code Playgroud)
并打电话
testEntityManager.flush();
Run Code Online (Sandbox Code Playgroud)
但同样,这感觉也不正确。如何在没有任何解决方法或附加语句的情况下使该测试失败?
在您的情况下,最简单的选项是配置@Transactional
注释,强制向数据库发送测试中的所有更改(它只能在特定的测试中使用):
import org.springframework.transaction.annotation.Propagation;
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);
}
}
Run Code Online (Sandbox Code Playgroud)
PD:由于您的存储库定义,我添加了一个简单的Integer
属性作为实体的 PK 。Employee
您可以在下图中看到结果:
小智 8
感谢医生的回答,我遇到了与OP类似的问题,你的解决方案有所帮助。我决定深入挖掘一下,找出它为什么有效,以防其他人遇到这个问题。
使用@DataJpaTest
带注释的测试类,您的类隐式地变为@Transactional
默认传播类型Propagation.REQUIRED
。这意味着每个测试方法也@Transactional
具有相同的默认配置。现在,所有 CRUD 方法也是CrudRepository
,@Transactional
但它与 无关@DataJpaTest
- 它们由于实现而具有事务性。哇,这么多交易!
一旦您用 注释整个类(或只是一个测试方法)@Transactional(propagation = Propagation.NOT_SUPPORTED)
,您的测试方法就不再是@Transactional
。但是,测试方法的内部方法(即来自 的 CRUD 操作)CrudRepository
仍然是事务性的,这意味着它们将具有自己的事务范围。因此,它们将在执行后立即提交到数据库,因为默认情况下(在使用 HikariCP 连接池的Spring Boot中),自动提交是打开的。自动提交发生在每个 SQL 查询之后。因此测试会如您所期望的那样通过。
我希望这可以帮到你。图中的 URL:
归档时间: |
|
查看次数: |
5261 次 |
最近记录: |