@DataSet
@Transactional(TransactionMode.ROLLBACK)
Class BeanTest extends UnitilsJunit4 {
  @SpringByType
  private IMonService service;
  @Test
  public test() {
    // ici on test notre service
    try {
      service.create(new Bean("toto"));
    } catch(Exception ex) {
      Assert.fail("erreur=" + ex);
    }
  }
}

Avec cette classe de test on va pouvoir tester les règles métier. On va également pouvoir tester les Validators Hibernate en désactivant la validation dans Hibernate et en la gérant "à la main" (avec l'AOP par exemple) au niveau des services de persistance. Par contre pour tester les contraintes d'unicité nous allons avoir un problème.

En effet, cette contrainte est gérée avec l'annotation Column qui est une annotation Jpa et qui n'est donc pas un Validator Hibernate. Lorsque la contrainte d'unicité est violée c'est la base de donnée qui va lever l'exception, la transmettre à Hibernate et remonter jusqu'au service.

Avec le mode transactionnel Unitils, le commit effectif est effectué dans l'équivalent du tearDown dans Unitils. Ceci implique que l'on ne peut pas catcher l'exception. On ne peut donc pas effectuer ce test correctement.

La solution est de désactiver le mode transactionnel

La solution à ce problème est de créer une classe spécifique pour le test de contrainte d'unicité, de désactiver le mode transactionnel et de tenter de créer deux fois un objet violant la contrainte d'unicité.

On se retrouve donc avec une classe qui ressemble à ça:

@DataSet
@Transactional(TransactionMode.DISABLED)
Class BeanTest extends UnitilsJunit4 {
  @SpringByType
  private IMonService service;
  @Test
  public test() {
    // ici on test notre service
    try {
      // ici toto doit être unique, une exception devrait être levée au second appel de create
      service.create(new Bean("toto"));
      service.create(new Bean("toto"));
      Assert.fail("erreur=" + ex);
    } catch(Exception ex) {
      // Le test devrait passer par là, on le cosidère dans ce cas comme OK
    }
  }
}

Je conseille également de spécifier la stratégie de chargement de la base CleanInsertLoadStrategy dans l'annotation DataSet.