San Jaisy
San Jaisy

Reputation: 17048

End-End test and Integration test in Micronaut using Test Container

I have a Micronaut application with the following structure

  1. API Gateway (Communicate with the producer)
  2. Product Producer (RabbitMq-Producer)
  3. Product Consumer (RabbitMq-Consumer)

Now I want to perform End-to-End and Integration testing for the application in local development and CI/CD.

I am using the RabbitMq Test container for the End-End and Integration testing.

CI/CD pipeline

After merging code and deployed the application to the server, run the integration and end-end test. Because producer and consumer will be running and all the test cases will work.

Local Development

Since the RabbitMQ Consumer is dependent on the Producer. While running Integration or End-to-End testing the Product producer application might not be running. So all the test case will be failed. A solution will be to run the producer application manually before running the tests.

Or Containerise all the applications and run the Test. What are the best practices for Integration or End-to-End testing in a microservice architecture?

Upvotes: 2

Views: 1343

Answers (1)

Anorgar
Anorgar

Reputation: 159

I hope I have understand the problem you have. I never tried RabbitMq test container so in my examples I will use first mongo with mongo test container, then elasticsearch with basic test container and specific image pull.

To launch properly test container in micronaut test, you have to first add dependencies in you build.gradle.

testCompile ("org.testcontainers:testcontainers:$testContainersVersion")
testCompile ("org.testcontainers:junit-jupiter:$testContainersVersion")
testCompile ("org.testcontainers:mongodb:$testContainersVersion")

Then you have to make a class test that will run the container(s) on a @BeforeAll method, this is really important because it is before the embedded server start.

import com.mongodb.BasicDBObject;
import com.mongodb.client.MongoClient;
import com.mongodb.client.MongoClients;
import io.micronaut.configuration.mongo.core.DefaultMongoConfiguration;
import io.micronaut.context.annotation.Value;
import io.micronaut.runtime.ApplicationConfiguration;
import io.micronaut.test.extensions.junit5.annotation.MicronautTest;
import org.junit.jupiter.api.BeforeAll;
import org.testcontainers.containers.MongoDBContainer;
import org.testcontainers.junit.jupiter.Container;

@MicronautTest
public class MongoIntegrationTest {

  @Container
  private static final MongoDBContainer mongoContainer = new MongoDBContainer("mongo:4.4.5").withExposedPorts(27017);

  private static boolean beforeAll = false;

  protected static MongoClient mongoClient;
  @Value("${mongo.database}")
  private String databaseName;
  @Value("${mongo.collection}")
  private String collectionName;

  @BeforeAll
  static void beforeAll() {
    if (beforeAll) {
      return;
    }
    beforeAll = true;
    mongoContainer.start();
    DefaultMongoConfiguration conf = new DefaultMongoConfiguration(new ApplicationConfiguration());
    conf.setUri(String.format("mongodb://%s:%s", mongoContainer.getHost(), mongoContainer.getFirstMappedPort()));
    mongoClient = MongoClients.create(conf.buildSettings());
  }

  protected void clearDatabases() {
    mongoClient.getDatabase(databaseName).getCollection(collectionName).deleteMany(new BasicDBObject());
  }
}

With this class, I create a mongo client directly linked to the container, then, I juste to use it instead of basic micronaut mongo client. I do this with a @MockBean

@MicronautTest
public class SearchControllerTest extends MongoIntegrationTest {

  @Inject
  private EmbeddedServer embeddedServer;
  @Inject
  private MongoRepository repository;

  @MockBean(MongoClient.class)
  public MongoClient getMongoClient() {
    return mongoClient;
  }
}

If you want to use a container and open the right port to make micronaut RabbitMq classes connect directly to it, you can use the fallowing:

@MicronautTest
public class ReturnBooksIndexerServiceTest {

  private static ElasticsearchContainer elsContainer;

  @Inject
  private ElsClient elsClient;

  @Inject
  private ElasticClient client;

  @BeforeAll
  public static void initContainer() {

    elsContainer = new ElasticsearchContainer("docker.elastic.co/elasticsearch/elasticsearch:7.10.1")
        .withExposedPorts(9200);
    elsContainer.getPortBindings().add("9200:9200");
    elsContainer.start();
  }
}

I hope those examples will help you start containers before the test runs. If I have not clearly understand the problem add comment below and I will try to edit.

Upvotes: 1

Related Questions