Issue
I have an Employee
entity with the following column:
@Entity
class Employee {
@Column(name = "first_name", length = 14)
private String firstName;
and I have a Spring JPA Repository for it:
@Repository
public interface EmployeeRepository extends CrudRepository<Employee, Integer> {
In test/resources/application.properties
I have the following so that I use an in-memory h2 database with tables auto-generated:
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
I was expecting this test to fail, since the firstName
is longer than what is allowed:
@DataJpaTest
public class EmployeeRepositoryTest {
@Autowired
private EmployeeRepository employeeRepository;
@Test
public void mustNotSaveFirstNameLongerThan14() {
Employee employee = new Employee();
employee.setFirstName("koraykoraykoray"); // 15 characters!
employeeRepository.save(employee);
}
}
And I was surprised to see this test was not failing, however the following does fail:
@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();
}
}
with the stacktrace:
Caused by: org.h2.jdbc.JdbcSQLDataException: Value too long for column "FIRST_NAME VARCHAR(14)": "'koraykoraykoray' (15)"; SQL statement:
The only difference is the second test has the additional employeeRepository.findAll();
statement, which forces Hibernate to flush as far as I understand.
This does not feel right to me, I would much rather want the test to fail immediately for save
.
I can also have
@Autowired
private TestEntityManager testEntityManager;
and call
testEntityManager.flush();
but again, this does not feel correct either.. How do I make this test fail without any workaround or additional statements?
Solution
The easiest option in your case is configure @Transactional
annotation, forcing to send database all changes in your tests (it can be used only in specific ones):
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: I have added a simple Integer
property as PK of Employee
entity due to your repository definition.
You can see the results in the following picture:
Answered By - doctore
Answer Checked By - Cary Denson (JavaFixing Admin)