HS6, Testing and @Transactional

I wanted to test my research in my springboot + hibernate application.

In order to do that I used the in memory index for the test configuration.

hibernate.search.backend.directory.type                      = local-heap
hibernate.search.automatic_indexing.synchronization.strategy = sync

And then made a dummy test, who create and saveAndFlush an entity that I then search:

@Test
public void testSearchBook() {
    String ean = "000000000001";
    Book book = createBook(ean);
    bookDao.saveAndFlush(book);

    SearchFilterDto filter = new SearchFilterDto();
    filter.setEan(ean);

    List<Book> results = bookService.searchBook(filter);
    assertThat(results.size()).isEqualTo(1);
}

With all my test classes extending:

@RunWith(SpringRunner.class)
@SpringBootTest
@Transactional
public abstract class BaseServiceTest

And I couldn’t get the test working, I tried to delay the search expecting that the indexing wasn’t fast enought but it didn’t changed the outcome.

I finally found out that the problem came from the @Transactional annotation (javax.transaction.Transactional).
If I remove it globally or just for this test with @Transactional(TxType.NEVER) then the test pass sucessfully.

Does someone know what side effects of @Transactional cause the test to fail ?

When you make changes to your database in a transaction, indexing happens on commit. That’s actually a good thing, and generally what you want in production.

However, if you annotate your test with @Transactional, the commit happens at the end of the test method. Thus indexing won’t happen until after your test is finished, and you will never see the result of indexing.

Either:

  • Move the logic you want to test to a separate component (database changes in one method, search query in another), and annotate that component with @Transactional
  • Or use Spring’s TransactionTemplates to explicitly wrap your data changes in one transaction, and your search query in another transaction (after the changes have been committed).

Thank you for responding so quickly.
I knew indexing was on commit but I wrongly assumed that a flush would provoke said commit.

I will keep the global @Transactional annotation since I like the default rollback by Spring for all the tests who don’t rely on indexes.

Since the data’s creation and the search are already executed in their own separate transactions I just need to remove the one on the test method (added by the global annotation) with @Transactional(TxType.NEVER).

And as mentionned here adding on the test method @DirtiesContext(methodMode = MethodMode.AFTER_METHOD) also renew the test context emptying datas and indexes for the next tests.