Explore o novo chatbot do Developer Center! O MongoDB AI chatbot pode ser acessado na parte superior da sua navegação para responder a todas as suas perguntas sobre o MongoDB .

Saiba por que o MongoDB foi selecionado como um líder no 2024 Gartner_Magic Quadrupnt()

Simplificando o desenvolvimento de aplicativos Java com o MongoDB: um guia abrangente para usar testcontainers

Aasawari Sahasrabuddhe6 min read • Published Jul 22, 2024 • Updated Jul 22, 2024
APLICATIVO COMPLETO
Facebook Icontwitter iconlinkedin icon
Classifique este artigo
star-empty
star-empty
star-empty
star-empty
star-empty
O mundo do desenvolvimento de software é um ciclo contínuo. Construímos, testamos, implementamos e iteramos – nos esforçando para fornecer aplicativos de alta qualidade. Dentro deste ciclo de vida de desenvolvimento de software (SDLC), o teste é crucial para garantir que nosso código funcione conforme o esperado. Existem dois tipos principais de testes que encontramos:
  1. Unit testing: In this part, the intent is to check if the business logic for the code is working well and if no unexpected results are formed.
  2. Integration testing: In this part of testing, the developer assesses how different parts of the system interact with each other. They simulate real-world scenarios by integrating with external dependencies. While providing a more holistic view of application behavior, traditional integration tests can be cumbersome to set up and maintain due to the need for external resources like databases.
O Testcontainers é uma estrutura de código aberto para Java que aproveita o poder dos contêineres do Docker para agilizar os testes de integração, criando instâncias leves e descartáveis de dependências reais nos contêineres do Docker durante o teste.
This tutorial will explore using Testcontainers with Java and Spring Boot, leveraging MongoDB as our database. We'll show you how to set up Testcontainers, integrate it into your project, and effectively use it to streamline your integration tests.
Vamos começar.

Pré-requisitos

  1. Java version 22 — download and install the latest JDK from the official Oracle website
  2. Maven version 3.9.6 — Download and install the latest version from the Maven official website
  3. Docker version 26.0.0 — Download and install Docker Desktop for your operating system from the official website

Introdução ao Testcontainers

Por que Testcontainers?

Como desenvolvedor de software, você navega por todas as fases do ciclo de vida de desenvolvimento de software durante o desenvolvimento de aplicativos. Quando a fase de desenvolvimento estiver concluída, a próxima etapa crítica envolve escrever casos de teste para verificar a lógica de negócios do aplicativo.
Independentemente de seu aplicativo ser desenvolvido usando Java vanilla ou Spring Boot, você normalmente escreverá testes JUnit para garantir que a lógica de negócios funcione corretamente e atenda aos requisitos especificados. Esses testes são essenciais para validar a funcionalidade do aplicativo e manter altos padrões de qualidade.
Para testar a funcionalidade completa do seu aplicativo, você também é obrigado a realizar testes de integração. O teste de integração é particularmente importante, pois se concentra nas interações entre diferentes módulos do software. Ele detecta problemas de interface e valida as relações funcionais e o fluxo de dados entre as unidades combinadas, garantindo que elas funcionem juntas perfeitamente. Isso é crucial para sistemas com vários componentes interconectados, pois melhora a confiabilidade e a estabilidade gerais da aplicação, garantindo que todas as peças se integrem corretamente e funcionem como um todo unificado.
Agora, suponhamos que seu aplicativo Java use MongoDB como banco de dados. Ao escrever seus testes JUnits, o que você prefere?
  1. Testando seus serviços com bancos de dados in-memory que também podem ser utilizados por outro módulo do aplicativo?
  2. Testando o aplicativo com o banco de dados criado localmente apenas para a lógica de negócios a ser testada?
Como parte da otimização do banco de dados, você escolheria a segunda opção acima.
Agora, é aqui que Testcontainers ajudaria a alcançar a segunda opção.
Vamos entender o conceito de Testcontainers na próxima seção.

Introdução ao Testcontainers

As quoted in the documentation for testcontainers:
Testcontainers for Java é uma biblioteca Java que suporta testes JUnit, fornecendo instâncias leves e descartáveis de bancos de dados comuns, navegadores Selenium ou qualquer outra coisa que possa ser executada em um container Docker.
Esses containers são gerenciados durante a execução do teste, garantindo um ambiente limpo e isolado para cada teste ou conjunto de testes. Ao aproveitar o Docker, o Testcontainers permite que os desenvolvedores automatizem a configuração e a desmontagem das dependências de teste, simplificando significativamente o processo de teste de integração.
Como já discutimos acima, o uso do Testcontainers oferece a vantagem de usar o banco de dados localmente, reduzindo a carga no banco de dados real usado pelos serviços.
Junto com isso, o Testcontainers também ajuda a fornecer:
  1. Consistência: It ensures that the tests run in a consistent environment, regardless of the underlying infrastructure.
  2. Isolamento: Each test can run in an isolated environment with its own set of dependencies.
  3. Up-to-date environments: This allows you to easily switch to different versions of dependencies by using different Docker images, which is particularly useful for testing compatibility with various versions of a database or service.

Trabalhando com Testcontainers

Até agora, você deve ter o conhecimento teórico sobre o que é Testcontainers e por que devemos usá-lo.
Nesta seção do artigo, discutiremos como os Testcontainers podem ser usados em Java e Spring Boot.
Isso será dividido em duas seções:
  1. Testcontainers com Java
  2. Testcontainers com Spring Boot
O conceito de Testcontainers permanece o mesmo, independentemente da estrutura em uso, mas essas duas seções ajudarão você a entender o aplicativo em ambos os cenários.
Para começar a usar o Testcontainers, você precisa carregar a dependência abaixo em seu arquivo pom.xml.
1 <dependency>
2 <groupId>org.mongodb</groupId>
3 <artifactId>mongodb-driver-sync</artifactId>
4 <version>5.1.0</version>
5 </dependency>
6 <dependency>
7 <groupId>org.junit.jupiter</groupId>
8 <artifactId>junit-jupiter-api</artifactId>
9 <version>5.10.2</version>
10 <scope>test</scope>
11 </dependency>
12 <dependency>
13 <groupId>org.junit.jupiter</groupId>
14 <artifactId>junit-jupiter-engine</artifactId>
15 <version>5.10.2</version>
16 <scope>test</scope>
17 </dependency>
18 <dependency>
19 <groupId>org.mockito</groupId>
20 <artifactId>mockito-core</artifactId>
21 <version>5.12.0</version>
22 <scope>test</scope>
23 </dependency>
24 <dependency>
25 <groupId>org.testcontainers</groupId>
26 <artifactId>testcontainers</artifactId>
27 <version>1.19.8</version>
28 <scope>test</scope>
29 </dependency>
30 <dependency>
31 <groupId>org.testcontainers</groupId>
32 <artifactId>junit-jupiter</artifactId>
33 <version>1.19.8</version>
34 <scope>test</scope>
35 </dependency>
36 <dependency>
37 <groupId>org.testcontainers</groupId>
38 <artifactId>mongodb</artifactId>
39 <version>1.19.8</version>
40 <scope>test</scope>
41 </dependency>

Testcontainers com shell Java

Os casos de teste escritos em testes JUnits são executados em três etapas com Testcontainers.
  1. Before tests: In this stage, the container is created, the database will be loaded, and collections will be created.
  2. During tests: This is the stage where the actual business logic of the application is tested.
  3. After tests: At this stage, the containers created in the first stage are destroyed and the resources are set free.
The code on how to use Testcontainers with Java is available in the Repositório do GitHub.
Neste exemplo de código, o caso de teste JUnits é escrito para testar uma consulta simples para localizar cinco nomes de filmes que tenham classificações IMDb maiores que sete.
The JUnits tests are written in the TestcontainerClass.java class and the below description will help you understand the code:
Se você observar o código, ele está dividido em quatro partes:
  • Creating container: This will pull the mongo:7.0.0 docker image from Docker Hub and create the container. The @Container annotation will start and stop the container when the tests are finished.
1@Container
2 private static final MongoDBContainer mongoDBContainer = new MongoDBContainer("mongo:7.0.0");
  • Setup: The container is started and the example documents are inserted inside testCollection.
1@BeforeAll
2 public void setup() {
3 String uri = mongoDBContainer.getConnectionString();
4 mongoClient = MongoClients.create(uri);
5 database = mongoClient.getDatabase("testdb");
6 collection = database.getCollection("testCollection");
7
8 // Insert sample data
9 Document doc1 = new Document("title", "Inception").append("imdb", new Document("rating", 8.8));
10 Document doc2 = new Document("title", "The Room").append("imdb", new Document("rating", 3.7));
11 Document doc3 = new Document("title", "The Dark Knight").append("imdb", new Document("rating", 9.0));
12
13 collection.insertMany(List.of(doc1, doc2, doc3));
14 }
  • Testes reais: The actual test case for the business logic is implemented.
1@Test
2 void testMoviesWithHighRating() {
3 List<Document> resultDocuments = new ArrayList<>();
4 try (MongoCursor<Document> cursor = collection.find(Filters.gt("imdb.rating", 7))
5 .projection(new Document("title", 1).append("_id", 0))
6 .limit(5)
7 .iterator()) {
8 while (cursor.hasNext()) {
9 Document doc = cursor.next();
10 System.out.println(doc.toJson());
11 resultDocuments.add(doc);
12 }
13 }
14
15 assertEquals(2, resultDocuments.size());
16 for (Document doc : resultDocuments) {
17 assertTrue(doc.containsKey("title"));
18 assertFalse(doc.containsKey("_id"));
19 }
20 }
In the above code example, when the sample data is loaded, the resultDocuments will contain an empty list.
Em seguida, no try-catch section of the code, the cursor iterates through the results, adding each document to the resultDocuments list after printing it in JSON format to the console. After the iteration, the test asserts that exactly two documents were retrieved by checking the size of the resultDocuments list.
Além disso, para cada documento na lista, o teste afirma que o campo title está presente e o campo _id está ausente. Essas afirmações garantem que a query se comporte conforme o esperado, recuperando o número correto de documentos com os campos apropriados.
Muitas vezes é confuso que os testes sejam criados no banco de dados de produção. Mas a vantagem de usar Testcontainers é que, quando você executa a classe de teste, a imagem do Docker é carregada, o documento de amostra é criado e os casos de teste são executados neste container. Após a conclusão dos testes, o container e a conexão são fechados.
Agora, vamos tentar entender como essa lógica pode ser implementada no framework Spring Boot.

Testcontainers com Spring Boot

To write JUnits tests in a Spring Boot application, we will utilize an old Repositório do GitHub that explains advanced aggregations using Spring Boot.
Neste repositório, você verá diferentes APIs REST criadas que funcionam na collection sample_supplies.sales .
Neste exemplo, vamos utilizá-lo apenas para escrever casos de teste para a API findAll().
The JUnits tests are similarly written in MongoDBSalesRepositoryTest.java.
  • Configurar o contêiner:
1@Container
2 public static MongoDBContainer mongoDBContainer = new MongoDBContainer(DockerImageName.parse("mongo:7.0.0"));
  • Insira dados no contêiner:
1@DynamicPropertySource
2 static void setProperties(DynamicPropertyRegistry registry) {
3 registry.add("spring.data.mongodb.uri", mongoDBContainer::getReplicaSetUrl);
4 registry.add("spring.data.mongodb.database", () -> "testdb");
5 }
6
7 @BeforeAll
8 public static void setUpAll() {
9 String mongoUri = mongoDBContainer.getConnectionString();
10 mongoClient = MongoClients.create(mongoUri);
11 }
12
13 @BeforeEach
14 public void setUp() {
15 salesRepository.save(createMockSales());
16 }
17
18 private Sales createMockSales() {
19 Item item1 = new Item("Item1", Arrays.asList("Tag1", "Tag2"), new BigDecimal("19.99"), 2);
20 Item item2 = new Item("Item2", Arrays.asList("Tag3", "Tag4"), new BigDecimal("29.99"), 1);
21 List<Item> items = Arrays.asList(item1, item2);
22
23 Customer customer = new Customer("Male", 30, "customer@example.com", 5);
24
25 return new Sales(new ObjectId(), new Date(), items, "Store1", customer, true, "Online");
26 }
  • Testes reais:
1 @Test
2 public void testFindAll() {
3 List<Sales> salesList = salesRepository.findAll();
4 assertThat(salesList).isNotEmpty();
5 assertThat(salesList.size()).isEqualTo(1);
6 Sales sales = salesList.get(0);
7 assertThat(sales.getStoreLocation()).isEqualTo("Store1");
8 assertThat(sales.getCustomer().getEmail()).isEqualTo("customer@example.com");
9 assertThat(sales.getItems()).hasSize(2);
10 }
O testFindAll method validates the findAll function of SalesRepository. It checks if at least one sales record is returned if there's exactly one record, and if its attributes match expected values like store location, customer email, and the number of items purchased. This test ensures the correctness of the repository's retrieval function.

Conclusão

Ao longo deste tutorial, demonstramos como configurar e usar Testcontainers para testes de integração com o MongoDB em um aplicativo Java básico e um aplicativo Spring Boot. Começamos adicionando as dependências necessárias ao nosso projeto, configurando o container do MongoDB e escrevendo casos de teste para validar nossa lógica de negócios. Seguindo essas etapas, é possível obter uma configuração de teste mais robusta e de fácil manutenção.
If you liked this article and wish to practice more such content, we encourage you to visit the MongoDB Developer Centre. You can also visit our community forums for meaningful discussions and documentation for more learning.
Principais comentários nos fóruns
Ainda não há comentários sobre este artigo.

Facebook Icontwitter iconlinkedin icon
Classifique este artigo
star-empty
star-empty
star-empty
star-empty
star-empty
Relacionado
Início rápido

Java - Change Streams


Oct 01, 2024 | 10 min read
Início rápido

Como criar um aplicativo CRUD com MongoDB, Quarkus e GraalVM


Aug 29, 2024 | 7 min read
Tutorial

Java encontra Queryable Encryption: desenvolvendo um aplicativo de conta bancária seguro


Oct 08, 2024 | 14 min read
Tutorial

Usando a autenticação AWS IAM com o conector MongoDB para Apache Kafka


Jul 01, 2024 | 4 min read