IT/ElasticSearch

Elasticsearch 단위테스트를 위한 testContainer사용하기

주현태 2021. 6. 1. 17:58

최근 우리팀의 코드는 모두 TDD로 작성되고 있다. TDD.. 뭔가 말로는 쉬워보였지만 막상 짜려니 손이 가지 않는다. 특히 Elasticsearch같은 다른 어플리케이션에 종속된 코드를 짤 때에는 특히 더 그렇다.

 

Kafka테스트의 경우 EmbeddedKafka를 이용하여 테스트를 진행하였는데, ES도 EmbeddedElasticsearch를 제공하지 않을까 하는 마음에 설레하며 찾아보았지만, 다음과 같은 답변을 볼 수 있었다.(https://discuss.elastic.co/t/in-memory-testing-with-resthighlevelclient/106196/5)

요약하자면, EmbeddedElasticsearch를 이전에는 제공하였지만, 이제 이 기능이 Deprecated되었고, 다른 것을 이용하여 test를 진행하라고 하는 것 같다. 그런데!! TestContainers라는 단어가 보인다.

 

이 기술은 일전에 TDD관련해서 우리팀 매니저님들중 한분이 testContainer라는 것을 사용하면 테스트시에 docker로 mysql을 띄울수 있다는 것을 소개해 주셨던 것이 떠올랐다.

 

리서치 끝에, 작동하는 코드를 만들었는데 그에 대해 글을 적어보도록 한다.

(공식문서는 다음과 같으니 참고한다. https://www.testcontainers.org/modules/elasticsearch/)

 

선행조건

일단, 선행되어야 하는 것은 test 코드가 실행되는 환경에 docker가 설치되어 있어야 함을 명심한다.

 

 

코드작성

build.gradle

// elasticsearch
implementation 'org.springframework.data:spring-data-elasticsearch:4.2.0'
implementation 'org.elasticsearch:elasticsearch:7.12.0'

testImplementation "org.testcontainers:elasticsearch:1.15.3"

 

테스트 코드.java

코드의 내용은 처음에 색인이 생성되지 않았으니 색인 존재여부가 false가 나오는 코드를 작성하고,

색인을 생성한 후에 색인존재여부를 확인하여 true가 나오는 코드이다. 

import org.apache.http.HttpHost;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.impl.client.BasicCredentialsProvider;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestClientBuilder;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.client.indices.CreateIndexRequest;
import org.elasticsearch.client.indices.GetIndexRequest;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.testcontainers.elasticsearch.ElasticsearchContainer;

import java.io.IOException;

import static org.assertj.core.api.Assertions.assertThat;


@SpringBootTest
public class IndexManageServiceTest
{
    @Autowired
    RestHighLevelClient client;

    @Test
    public void test() throws IOException
    {
        ElasticsearchContainer container
            = new ElasticsearchContainer("docker.elastic.co/elasticsearch/elasticsearch:7.12.0");
        container.start();

        BasicCredentialsProvider credentialProvider = new BasicCredentialsProvider();
        credentialProvider.setCredentials(AuthScope.ANY,
            new UsernamePasswordCredentials("elasticsearch", "elasticsearch"));

        RestClientBuilder builder = RestClient.builder(HttpHost.create(container.getHttpHostAddress()))
            .setHttpClientConfigCallback(
                httpClientBuilder -> httpClientBuilder.setDefaultCredentialsProvider(credentialProvider)
            );

        RestHighLevelClient client = new RestHighLevelClient(builder);
        // index생성전 index가 존재하는지 확인
        boolean isIndexExists = client.indices().exists(new GetIndexRequest("test_index"), RequestOptions.DEFAULT);
        assertThat(isIndexExists).isEqualTo(false);

        client.indices().create(new CreateIndexRequest("test_index"), RequestOptions.DEFAULT);

        // index생성후 index가 존재하는지 확인
        isIndexExists = client.indices().exists(new GetIndexRequest("test_index"), RequestOptions.DEFAULT);
        assertThat(isIndexExists).isEqualTo(true);
    }
}

정상작동함을 확인할 수 있었다. 이를 이용하여 다양한 테스트 코드 작성이 가능할것 같다는 생각에 기쁘다.