Search code examples
spring-bootelasticsearchintegration-testing

Use different elastic index for test in Spring Boot


I have a Spring Boot project that uses ElasticSearch for storing and indexing Products. Product model is:

@Document(indexName = "products", type = "product")
public class Product {

@Id
public String id;
private String[] barcode;
private String name;
private String description;
private String image;
private String detail;
private double price;
private double gain;
private List<Category> categories;
private Currency currency;
private boolean eliminated;
private String taxDescription;
private double taxRate;
private int taxId;

}

I am doing integration tests for operation on Products, like search, update, etc, and I need to use the same elastic server. I am thinking about creating an index during just for test purposes,fill it with some products, and after tests, just delete it. Is it possible? How can I do that?


Solution

  • I assume that you are using the well-known Spring Data Repositories in your production code. Something like this may reside in your project:

    @Repository
    public interface ProductRepository extends ElasticsearchRepository<Product, String> {
        Product findByName(String name);
    }
    

    So you could setup a small integration test case like the following:

    @SpringBootTest
    @RunWith(SpringRunner.class)
    public class QueryIndexIT {
        @Autowired
        private ProductRepository repo;
        @Autowired
        private ElasticsearchTemplate template;
    
        @Test
        public void queryRepo() {
            assertThat(template.indexExists(Product.class)).isTrue();
    
            Product savedProduct = repo.save(new Product(null, "the name", "n/a"));
            Product foundProduct = repo.findByName("the name");
    
            assertThat(foundProduct).isEqualTo(savedProduct);
        }
    }
    }
    

    So basically you're running this integration test with the Spring context you are familiar with, maybe altered a little bit via application-test.properties.

    To be independent from any real-life ElasticSearch servers in your network you could also decouple yourself by using the Maven Docker Plugin. Pay special attention to the executions section listed below in my pom.xml snippet. It starts a new ElasticSearch container before any integration tests run and removes it as soon as the tests terminated. So you start each test cycle with a clean and stable test setup:

                <plugin>
                    <groupId>io.fabric8</groupId>
                    <artifactId>docker-maven-plugin</artifactId>
                    <version>0.28.0</version>
                    <configuration>
                        <showLogs>true</showLogs>
                        <verbose>true</verbose>
                        <removeVolumes>true</removeVolumes>
                        <allContainers>true</allContainers>
                        <images>
                            <image>
                                <name>elasticsearch:6.6.2</name>
                                <alias>elasticsearch</alias>
                                <run>
                                    <ports>
                                        <port>9200:9200</port>
                                        <port>9300:9300</port>
                                    </ports>
                                    <env>
                                        <ES_JAVA_OPTS>-Xms512m -Xmx512m</ES_JAVA_OPTS>
                                        <cluster.name>docker-cluster</cluster.name>
                                        <discovery.type>single-node</discovery.type>
                                    </env>
                                </run>
                            </image>
                        </images>
                    </configuration>
                    <executions>
                        <execution>
                            <id>prepare-containers</id>
                            <phase>pre-integration-test</phase>
                            <goals>
                                <goal>stop</goal>
                                <goal>start</goal>
                            </goals>
                        </execution>
                        <execution>
                            <id>remove-containers</id>
                            <phase>post-integration-test</phase>
                            <goals>
                                <goal>stop</goal>
                            </goals>
                        </execution>
                    </executions>
                </plugin>
    

    You can find more information on the referenced ElasticSearch Docker image in its description on the Docker Hub.

    So you noticed, that it is not necessary to create a separate index just for testing purposes. Keep test and production code (and config where possible) closely together to avoid surprises at production runtime.

    If you want to remedy possible issues with your setup, you could also compare your approach with a running example which I prepared for you in my Github repository.

    Just try it with mvn clean verify -Dit.test=QueryIndexIT. Have fun and come back with your progress or remarks!