Writing Tests that Exercise Hibernate Search

I used Hibernate Search when it first came out. I have come back to it on a project where we are using Java 19 and Hibernate trying to layer in search. The project was created with Springboot 2.7.x.

I made the mistake of trying to make a JpaDataTest and then do some searches. I have gotten to the point now where it should be working but I am seeing this:

HSEARCH000027: Mass indexing is going to index 0 entities.

Probably has something to do with TX, but I put some code into the test to make sure the insertions do get committed.

package com.xumo.features.model;

import org.hibernate.search.engine.search.query.SearchResult;
import org.hibernate.search.mapper.orm.Search;
import org.hibernate.search.mapper.orm.massindexing.MassIndexer;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
import org.springframework.transaction.support.TransactionTemplate;

import javax.persistence.EntityManager;
import java.time.Duration;
import java.util.function.Supplier;

import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.greaterThan;
import static org.hamcrest.Matchers.is;

@DataJpaTest
public class ContentSearchTest {

    private final Logger log = LoggerFactory.getLogger(ContentSearchTest.class);

    @Autowired
    private EntityManager entityManager;

    @Autowired
    private ContentRepository contentRepository;

    @Autowired
    TransactionTemplate txTemplate;

    private <T> T doInTransaction(Supplier<T> operation) {
        return txTemplate.execute(status -> operation.get());
    }

    private void doInTransaction(Runnable operation) {
        txTemplate.execute(status -> {
            operation.run();
            return null;
        });
    }

    @BeforeEach
    public void setup() throws InterruptedException {
        Movie dirtyHarry = new Movie("Dirty Harry");
        Movie magnumForce = new Movie("Magnum Force", "Sequel to dirty harry.", Duration.ofMinutes(103));
        Movie fortyEightHours = new Movie("48 Hours");

        doInTransaction(() -> {
            contentRepository.save(dirtyHarry);
            contentRepository.save(magnumForce);
            contentRepository.save(fortyEightHours);
            entityManager.flush();
        });

        Search.session(entityManager).massIndexer(Content.class).startAndWait();
    }

    @Test
    public void canSearchContent() {

        //List<Content> results = contentRepository.searchBy("Dirty harry", 10, "title", "description");

        SearchResult<Content> results = Search.session(entityManager)
                .search(Content.class)
                .where(f -> f.match().fields("title", "description")
                        .matching("Dirty Harry ").fuzzy(2))
                .fetch(10);

        log.info("search result: " + results);

        assertThat(contentRepository.findAll().iterator().hasNext(), is(true));

        for (Content content : contentRepository.findAll()) {
            log.info("found: [" + content.getTitle() + " " + content.getDescription() + "]");
        }
        assertThat(results.total().hitCount(), greaterThan(0L));

    }
}

Hi Rob, thanks for reaching out

that’s most likely the case. By the way, you might be interested in this repository - hibernate-search/integrationtest/showcase/library at main · hibernate/hibernate-search · GitHub It includes a Spring app example as well as some tests. In particular, there’s a test for mass indexing.

Hi @mbekhta thanks for the response. Yes I had looked at that repo. Where is the test that invokes the mass indexer?? I just see the Java17Service, which I had seen before. It’s kind of interesting how sparse that is. I started trying to implement this: Build a Spring Boot REST API with Full-Text Search using Hibernate Search - Spring Cloud. OMG, huge waste of time. Convinced myself that their interface extension is not possible. Then found that example project and saw the bare bones approach on full display.

How depressing is it that this product has been out for over a decade and this isn’t covered 10 ways to Sunday in guides and with example tests?? I thought that was Spring and Hibernate’s strong suit, lol.

Oh ok clicked the 2nd link, I had seen that before too.

Guys, this is a fixture. Not sure if you have ever seen ScalaTest. They have a whole huge array of test fixtures. Make a fixture! You get your data stuffed in and indexed, then your tests run, then the data is gone!

Good news: I got this to work. Combination of doing doInTransaction and I had been using @DataJpaTest changed to @SpringbootTest at the end and bingo.

Also, on my other ticket, I did get that sorted: indexing subs but fetching abstract base types. So pretty happy. Thanks for the help.