Сквозной тест и интеграционный тест в Micronaut с использованием тестового контейнера

#java #junit #rabbitmq #microservices #micronaut

Вопрос:

У меня есть приложение Micronaut со следующей структурой

  1. Шлюз API (связь с производителем)
  2. Производитель продукции (RabbitMQ-Производитель)
  3. Потребитель продукта (RabbitMQ-Потребитель)

Теперь я хочу выполнить сквозное и интеграционное тестирование приложения в локальной разработке и CI/CD.

Я использую тестовый контейнер RabbitMQ для конечного и интеграционного тестирования.

Трубопровод CI/CD

После объединения кода и развертывания приложения на сервере запустите интеграцию и конечный тест. Потому что производитель и потребитель будут запущены, и все тестовые случаи будут работать.

Местное Развитие

Поскольку потребитель RabbitMQ зависит от Производителя. Во время выполнения интеграции или сквозного тестирования приложение производителя продукта может не работать. Таким образом, все тестовые задания будут провалены. Решением будет запуск приложения-производителя вручную перед запуском тестов.

Или соберите все приложения в контейнер и запустите тест. Каковы наилучшие методы интеграции или сквозного тестирования в архитектуре микросервиса?

Комментарии:

1. Привет, я использую много тестовых контейнеров с micronaut, и перед запуском тестового встроенного сервера можно запустить контейнеры (в нужном вам порядке). Но действительно ли вам нужен api-интерфейс шлюза между кроликом и сервисом, который вы тестируете ? Если ваша проблема в том, как запустить докер, а затем запустить интеграционный тест, я могу привести пример. Если у вас тоже возникнут проблемы со шлюзом, я, возможно, не смогу вам помочь

2. @Anorgar, пожалуйста, ваша помощь будет оценена по достоинству.

3. «Каковы наилучшие методы интеграции или сквозного тестирования в архитектуре микросервиса?» — Есть многое, что нужно обсудить в рамках ответа на этот вопрос. Этот вопрос был бы более согласован с руководящими принципами SO, если бы он был более целенаправленным.

4. github.com/micronaut-projects/micronaut-core/discussions это хорошее место для начала более общих дискуссий.

Ответ №1:

Надеюсь, я понял, в чем ваша проблема. Я никогда не пробовал тестовый контейнер RabbitMQ, поэтому в своих примерах я буду использовать сначала mongo с тестовым контейнером mongo, затем elasticsearch с базовым тестовым контейнером и конкретным извлечением изображения.

Чтобы правильно запустить тестовый контейнер в тесте micronaut, вам необходимо сначала добавить зависимости в файл build.gradle.

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

Затем вам нужно выполнить тест класса, который запустит контейнер(ы) в методе @beforeAll, это действительно важно, потому что это происходит до запуска встроенного сервера.

 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());
  }
}
 

С помощью этого класса я создаю клиент mongo, напрямую связанный с контейнером, а затем просто использую его вместо базового клиента micronaut mongo. Я делаю это с помощью @MockBean

 @MicronautTest
public class SearchControllerTest extends MongoIntegrationTest {

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

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

Если вы хотите использовать контейнер и открыть нужный порт, чтобы классы micronaut RabbitMQ подключались непосредственно к нему, вы можете использовать паровую:

 @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();
  }
}
 

Я надеюсь, что эти примеры помогут вам запустить контейнеры до начала тестовых запусков. Если я не совсем понял проблему, добавьте комментарий ниже, и я попытаюсь отредактировать.