Hibernate Search 6 - JUnit testing

Hi everyone,

we’ve just implemented Hibernate Search 6 with Elastic Search in our project (that uses Spring Boot) and now try to write unit tests for our code. What are the best approaches for writing tests for Hibernate Search 6? How can we fill the entity manager with some test data and test if the search queries are returning the excepted results?

First, we were struggling to include the EntityManager in our tests. When using

@PersistedConext
Private Entitymanager entityManager;

It fails because the entity manager is null. Because we’re using Spring Boot we didn’t define a persistence.xml because we rely on Spring Boot to set it up. After we set up the entity manager correctly with the entity manager factory we’re facing some other problems setting up some in memory database.

final LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
em.setJpaVendorAdapter(new HibernateJpaVendorAdapter());
em.setPersistenceProviderClass(HibernatePersistenceProvider.class);
em.setPackagesToScan("com.foobar.search”);
em.afterPropertiesSet();

But now Hibernate Search complains that it doesn’t find a default_backend and we’re feeling that our tests does a bit too much in order to just test the search functionality (setting up an in memory database, defining the entity manager and so on). So our question now is: what is the best approach to set up tests for Hibernate Search 6 and if we’re on the wrong track or what we need to define in our to correctly set this up.

Thanks in advance!

I’m sure there are as many ways to test an application as there are developers, but I’ll try to give you my opinion.

You have to distinguish between two things:

  1. The business logic of your application, usually implemented in “services”.
  2. The data access layers of your application, usually implemented in “repositories” (at least in the Spring Data world).

Usually services depend on the data access layer.

When you test your services, it may indeed be a good idea to keep the configuration to a minimum. You can achieve this by mocking your repositories: then, you won’t need Hibernate ORM, Hibernate Search, the database or Elasticsearch.

When you test your repositories, I don’t think mocking is a good idea. A lot of the errors you’re likely to encounter will only be detected by Hibernate ORM, the database, Hibernate Search or Elasticsearch. If you mock them, you won’t see the errors.

Take for example the search DSL of Hibernate Search: Hibernate Search performs validation of the arguments you pass to the predicates, and throws an exception when a argument has an incorrect type, for example. If you mock Hibernate Search, you won’t see that.

Another example: in your Hibernate Search mapping, you are free to reference analyzers with any name, because some analyzers can be defined on the server side in Elasticsearch. Upon startup, Hibernate Search will push the mapping to Elasticsearch, and Elasticsearch will validate that every analyzer referenced in your mapping actually exists. If you mock Elasticsearch, you won’t see invalid analyzer references.

There are many examples like this, and in the end I think it’s much safer to just write integration tests for your repositories, not unit tests. Of course you don’t need to write full-stack integration tests: you can still mock repositories when you test your services. But the repositories, in my opinion, should be tested in an environment as close to your production as possible.

This means spinning up a database, H2 if you must, but ideally the same one you’ll use in production (using a container for example). This also means spinning up an Elasticsearch instance.

There are tools do integrate this to your Maven build, such as the elasticsearch-maven-plugin, and probably other plugins to spin up containers using docker. But if you don’t want any of this, you can also disable the integration tests by default, and only activate them with a specific Maven profile in your continuous integration job (Jenkins, Travis, …) where the database and Elasticsearch are already configured.

Regarding the configuration of the datasource in Spring and the backend in Hibernate Search, I don’t think you will need much. You basically only need to configure the JDBC URL and the Elasticsearch URL; everything else can be included in your core settings as you will need the exact same settings for production and integration tests.

If you’re interested in an example, we have a Spring showcase in the Hibernate Search integration tests: https://github.com/hibernate/hibernate-search/tree/master/integrationtest/showcase/library
This includes a production configuration in src/main/resources (using environment variables for the bits we don’t want in the source) and the necessary overrides in src/test/resources.
However, in our case we only used H2, and we tested the whole application in integration tests, not just repositories.