Prise en charge de Testcontainers par Spring Cloud Azure

Cet article explique comment intégrer Spring Cloud Azure à Testcontainers pour écrire des tests d’intégration efficaces pour vos applications.

Testcontainer est une infrastructure open source permettant de fournir des instances légères de bases de données, de répartiteurs de messages, de navigateurs web ou tout ce qui peut s’exécuter dans un conteneur Docker. Il s’intègre à JUnit, ce qui vous permet d’écrire une classe de test qui peut démarrer un conteneur avant l’exécution de l’un des tests. Testcontainer est particulièrement utile pour écrire des tests d’intégration qui parlent à un service principal réel.

La bibliothèque spring-cloud-azure-testcontainers prend désormais en charge les tests d’intégration pour les services Azure suivants :

Connexions de service

Une connexion de service est une connexion à n’importe quel service distant. La configuration automatique de Spring Boot peut consommer les détails d’une connexion de service et les utiliser pour établir une connexion à un service distant. Dans ce cas, les détails de la connexion sont prioritaires sur toutes les propriétés de configuration liées à la connexion.

Lorsque vous utilisez Testcontainers, vous pouvez créer automatiquement des détails de connexion pour un service s’exécutant dans un conteneur en annotant le champ conteneur dans la classe de test.

xxxContainerConnectionDetailsFactory les classes sont enregistrées auprès de spring.factories. Ces fabriques créent un haricot ConnectionDetails en fonction d’une sous-classe Container spécifique ou du nom de l’image Docker.

Le tableau suivant fournit des informations sur les classes de fabrique de détails de connexion prises en charge par le JAR spring-cloud-azure-testcontainers :

Classe de fabrique des détails de connexion Détails de connexion bean
CosmosContainerConnectionDetailsFactory AzureCosmosConnectionDetails
StorageBlobContainerConnectionDetailsFactory AzureStorageBlobConnectionDetails
StorageQueueContainerConnectionDetailsFactory AzureStorageQueueConnectionDetails
EventHubsContainerConnectionDetailsFactory AzureEventHubsConnectionDetails
ServiceBusContainerConnectionDetailsFactory AzureServiceBusConnectionDetails

Configurer des dépendances

La configuration suivante configure les dépendances requises :

  <properties>
    <version.spring.cloud.azure>7.4.0</version.spring.cloud.azure>
  </properties>

  <dependencyManagement>
    <dependencies>
      <dependency>
        <groupId>com.azure.spring</groupId>
        <artifactId>spring-cloud-azure-dependencies</artifactId>
        <version>${version.spring.cloud.azure}</version>
        <type>pom</type>
        <scope>import</scope>
      </dependency>
    </dependencies>
  </dependencyManagement>

  <dependencies>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-test</artifactId>
      <scope>test</scope>
    </dependency>
    <dependency>
      <groupId>org.testcontainers</groupId>
      <artifactId>testcontainers-junit-jupiter</artifactId>
      <scope>test</scope>
    </dependency>
    <dependency>
      <groupId>com.azure.spring</groupId>
      <artifactId>spring-cloud-azure-testcontainers</artifactId>
      <scope>test</scope>
    </dependency>
    <dependency>
      <groupId>com.azure.spring</groupId>
      <artifactId>spring-cloud-azure-starter-cosmos</artifactId>
      <scope>test</scope>
    </dependency>
  </dependencies>

Utiliser Testcontainers

L’exemple de code suivant illustre l’utilisation de base des Testcontainers :

@SpringBootTest(classes = CosmosTestcontainersTest.class)
@Testcontainers
@ExtendWith(SpringExtension.class)
@ImportAutoConfiguration(classes = { AzureGlobalPropertiesAutoConfiguration.class, AzureCosmosAutoConfiguration.class})
public class CosmosTestcontainersTest {

    @TempDir
    private static File tempFolder;

    @Autowired
    private CosmosClient client;

    @Container
    @ServiceConnection
    static CosmosDBEmulatorContainer cosmos = new CosmosDBEmulatorContainer(
        DockerImageName.parse("mcr.microsoft.com/cosmosdb/linux/azure-cosmos-emulator:latest"))
                .waitingFor(Wait.forHttps("/_explorer/emulator.pem").forStatusCode(200).allowInsecure())
                .withStartupTimeout(Duration.ofMinutes(3));

    @BeforeAll
    public static void setup() throws IOException, CertificateException, KeyStoreException, NoSuchAlgorithmException {
        Path keyStoreFile = new File(tempFolder, "azure-cosmos-emulator.keystore").toPath();
        KeyStore keyStore = cosmos.buildNewKeyStore();
        try (var out = Files.newOutputStream(keyStoreFile.toFile().toPath())) {
            keyStore.store(out, cosmos.getEmulatorKey().toCharArray());
        }

        System.setProperty("javax.net.ssl.trustStore", keyStoreFile.toString());
        System.setProperty("javax.net.ssl.trustStorePassword", cosmos.getEmulatorKey());
        System.setProperty("javax.net.ssl.trustStoreType", "PKCS12");
    }

    @Test
    public void test() {
        CosmosDatabaseResponse databaseResponse = client.createDatabaseIfNotExists("Azure");
        assertThat(databaseResponse.getStatusCode()).isEqualTo(201);
        CosmosContainerResponse containerResponse = client
            .getDatabase("Azure")
            .createContainerIfNotExists("ServiceContainer", "/name");
        assertThat(containerResponse.getStatusCode()).isEqualTo(201);
    }

}

Pour utiliser CosmosDBEmulatorContainer, vous devez préparer un KeyStore pour TLS/SSL. Pour plus d’informations, consultez le module Azure Cosmos DB dans la documentation de Testcontainers. Avec @ServiceConnection, cette configuration permet aux beans associés à Cosmos DB dans l’application de communiquer avec Cosmos DB exécuté dans le conteneur Docker géré par Testcontainers. Cette configuration définit automatiquement une AzureCosmosConnectionDetails bean, que la configuration automatique Cosmos DB utilise ensuite pour remplacer les propriétés de configuration liées à la connexion.

Échantillons

Pour plus d’informations, consultez les spring-cloud-azure-testcontainers exemples.