Search code examples
kotlinspring-data-jpaunique-constraintdatabase-testing

Testing unique constraint in @DataJpaTest


I wrote this test to verify unique constraint on Domain.name in the database. But it doesn't work: I expect an exception to be thrown on the domainRepository.saveAndFlush(domainDuplicate) operation, but the test ends successfully.

@RunWith(SpringRunner::class)
@DataJpaTest
class DomainRepositoryTest {

    @Autowired
    private lateinit var util: TestEntityManager
    @Autowired
    private lateinit var domainRepository: DomainRepository

    @Test
    fun testNonUniqueDomainSave() {
        // Arrange
        val domain = Domain(name = "name")
        util.persist(domain)
        util.flush()
        util.clear()

        val domainDuplicate = domain.copy(id = 0L)

        // Act
        domainRepository.saveAndFlush(domainDuplicate)
        // Exception is expected
    }
}

Test log (shortened):

INFO 13522 --- [           main] o.s.t.c.transaction.TransactionContext   : Began transaction (1) for test context [DefaultTestContext@8f8717b testClass = DomainRepositoryTest,...]; transaction manager [org.springframework.orm.jpa.JpaTransactionManager@65f36591]; rollback [true]

Hibernate: insert into domains (name, id) values (?, ?)
Hibernate: insert into domains (name, id) values (?, ?)
Hibernate: insert into domains (name, id) values (?, ?)

INFO 13522 --- [           main] o.s.t.c.transaction.TransactionContext   : Rolled back transaction for test: [DefaultTestContext@8f8717b testClass = DomainRepositoryTest, ...], attributes = map[[empty]]]

Question: How to fix this test? Additional question: Why 3 insert operations in log?

Database: H2


Solution

  • It was a problem with database initialization in tests: there was no unique constraint! I assumed that Liquibase should run migrations before any tests but in fact, it was not configured to do so. By default, Hibernate DDL auto update is used to create DB schema in tests.

    I can think of 2 possible solutions:

    1. add liquibase-core jar to test classpath and configure it to run migrations
    2. declare @UniqueConstraint on domain entity and rely on Hibernate DDL.