Compatibilidad de Spring Cloud con Azure para Testcontainers

En este artículo se describe cómo integrar Spring Cloud Azure con Testcontainers para escribir pruebas de integración eficaces para las aplicaciones.

Testcontainer es un framework de código abierto que permite proporcionar instancias desechables y ligeras de bases de datos, brokers de mensajes, navegadores web o prácticamente cualquier cosa que pueda ejecutarse en un contenedor de Docker. Se integra con JUnit, lo que le permite escribir una clase de prueba que pueda iniciar un contenedor antes de que se ejecute cualquiera de las pruebas. Testcontainer es especialmente útil para escribir pruebas de integración que hablan con un servicio back-end real.

La biblioteca de spring-cloud-azure-testcontainers ahora admite pruebas de integración para los siguientes servicios de Azure:

Conexiones de servicio

Una conexión de servicio es una conexión a cualquier servicio remoto. La configuración automática de Spring Boot puede consumir los detalles de una conexión de servicio y usarlas para establecer una conexión a un servicio remoto. Al hacerlo, los detalles de conexión tienen prioridad sobre las propiedades de configuración relacionadas con la conexión.

Al usar Testcontainers, puede crear automáticamente detalles de conexión para un servicio que se ejecuta en un contenedor anotando el campo contenedor en la clase de prueba.

xxxContainerConnectionDetailsFactory Las clases se registran con spring.factories. Estas factorías crean un bean ConnectionDetails basado en una subclase Container específica o en el nombre de la imagen de Docker.

En la siguiente tabla se proporciona información sobre las clases de generador de detalles de conexión admitidas en el archivo JAR spring-cloud-azure-testcontainers:

Clase de fábrica de detalles de la conexión Bean de detalles de la conexión
CosmosContainerConnectionDetailsFactory AzureCosmosConnectionDetails
StorageBlobContainerConnectionDetailsFactory AzureStorageBlobConnectionDetails
StorageQueueContainerConnectionDetailsFactory AzureStorageQueueConnectionDetails
EventHubsContainerConnectionDetailsFactory AzureEventHubsConnectionDetails
ServiceBusContainerConnectionDetailsFactory AzureServiceBusConnectionDetails

Configuración de dependencias

La siguiente configuración configura las dependencias necesarias:

  <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>

Uso de Testcontainers

En el ejemplo de código siguiente se muestra el uso básico de 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);
    }

}

Para usar CosmosDBEmulatorContainer, debe preparar un KeyStore para TLS/SSL. Para más información, consulte Cosmos DB Azure Module en la documentación de Testcontainers. Con @ServiceConnection, esta configuración permite que los beans de la aplicación relacionados con Cosmos DB se comuniquen con Cosmos DB, que se ejecuta dentro del contenedor Docker gestionado por Testcontainers. Esta configuración define automáticamente un AzureCosmosConnectionDetails bean, que la configuración automática de Cosmos DB usa para invalidar las propiedades de configuración relacionadas con la conexión.

Muestras

Para obtener más información, consulte los spring-cloud-azure-testcontainers ejemplos.