J'ai une entité Employee avec la colonne suivante:

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

Et j'ai un référentiel Spring JPA pour cela:

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

Dans test/resources/application.properties, j'ai ce qui suit pour utiliser une base de données h2 en mémoire avec des tables générées automatiquement:

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

Je m'attendais à ce que ce test échoue, car le firstName est plus long que ce qui est autorisé:

@DataJpaTest
public class EmployeeRepositoryTest {

  @Autowired
  private EmployeeRepository employeeRepository;

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

Et j'ai été surpris de voir que ce test n'échouait pas, mais ce qui suit échoue:

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

Avec le stacktrace:

Caused by: org.h2.jdbc.JdbcSQLDataException: Value too long for column "FIRST_NAME VARCHAR(14)": "'koraykoraykoray' (15)"; SQL statement:

La seule différence est que le deuxième test a l'instruction supplémentaire employeeRepository.findAll();, qui force Hibernate à vider autant que je comprends.

Cela ne me semble pas juste, je préférerais de loin que le test échoue immédiatement pour save.

Je peux aussi avoir

@Autowired
private TestEntityManager testEntityManager;

Et appeler

testEntityManager.flush();

Mais encore une fois, cela ne semble pas non plus correct. Comment faire échouer ce test sans solution de contournement ni instructions supplémentaires?

3
Koray Tugay 7 sept. 2020 à 20:52

2 réponses

Meilleure réponse

L'option la plus simple dans votre cas est de configurer l'annotation @Transactional, obligeant à envoyer à la base de données toutes les modifications de vos tests (elle ne peut être utilisée que dans des tests spécifiques):

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: j'ai ajouté une propriété Integer simple en tant que PK de l'entité Employee en raison de la définition de votre référentiel.

Vous pouvez voir les résultats dans l'image suivante:

Reposity tests

2
doctore 10 sept. 2020 à 08:01

Vous pouvez utiliser JpaRepository<T,ID> au lieu de CrudRepository<T,ID>. Quelque chose comme:

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

Ensuite, vous pouvez utiliser sa méthode saveAndFlush() partout où vous avez besoin d'envoyer des données immédiatement:

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

Et dans le code où vous souhaitez avoir une optimisation, vous pouvez toujours utiliser la méthode save().

1
Koray Tugay 27 sept. 2020 à 01:36