Uma conexão de serviço é uma conexão com qualquer serviço remoto. A configuração automática do Spring Boot pode consumir os detalhes de uma conexão de serviço e usá-los para estabelecer uma conexão com um serviço remoto. Ao fazer isso, os detalhes da conexão têm precedência sobre quaisquer propriedades de configuração relacionadas à conexão.
Ao usar Testcontainers, você pode criar automaticamente detalhes de conexão para um serviço em execução em um contêiner anotando o campo de contêiner na classe de teste.
A tabela a seguir fornece informações sobre as classes de fábrica de detalhes de conexão com suporte no JAR spring-cloud-azure-testcontainers:
<properties>
<version.spring.cloud.azure>7.1.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>
<properties>
<version.spring.cloud.azure>7.1.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-storage-blob</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<properties>
<version.spring.cloud.azure>7.1.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-storage-queue</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<properties>
<version.spring.cloud.azure>7.1.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-eventhubs</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<properties>
<version.spring.cloud.azure>7.1.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-stream-binder-eventhubs</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<properties>
<version.spring.cloud.azure>7.1.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</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.azure.spring</groupId>
<artifactId>spring-messaging-azure-servicebus</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.microsoft.sqlserver</groupId>
<artifactId>mssql-jdbc</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<properties>
<version.spring.cloud.azure>7.1.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-stream-binder-servicebus</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.microsoft.sqlserver</groupId>
<artifactId>mssql-jdbc</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
@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, você precisa preparar um KeyStore para TLS/SSL. Para obter mais informações, consulte Módulo do Azure do Cosmos DB na documentação de Testcontainers. Com @ServiceConnection, essa configuração permite que os feijões relacionados ao Cosmos DB no aplicativo se comuniquem com o Cosmos DB em execução dentro do contêiner do Docker gerenciado por Testcontainers. Essa configuração define automaticamente um AzureCosmosConnectionDetails bean, que a configuração automática do Cosmos DB usa para substituir as propriedades de configuração relacionadas à conexão.
@SpringJUnitConfig
@Testcontainers
class StorageBlobTestcontainersTest {
@Container
@ServiceConnection
private static final GenericContainer<?> AZURITE_CONTAINER = new GenericContainer<>(
"mcr.microsoft.com/azure-storage/azurite:latest")
.withExposedPorts(10000)
.withCommand("azurite --skipApiVersionCheck && azurite -l /data --blobHost 0.0.0.0 --queueHost 0.0.0.0 --tableHost 0.0.0.0");
@Value("azure-blob://testcontainers/message.txt")
private Resource blobFile;
@Test
void test() throws IOException {
String originalContent = "Hello World!";
try (OutputStream os = ((WritableResource) this.blobFile).getOutputStream()) {
os.write(originalContent.getBytes());
}
String resultContent = StreamUtils.copyToString(this.blobFile.getInputStream(), Charset.defaultCharset());
assertThat(resultContent).isEqualTo(originalContent);
}
@Configuration(proxyBeanMethods = false)
@ImportAutoConfiguration(classes = {AzureGlobalPropertiesAutoConfiguration.class, AzureStorageBlobAutoConfiguration.class, AzureStorageBlobResourceAutoConfiguration.class})
static class Config {
}
}
Com @ServiceConnection, essa configuração permite que os feijões relacionados a blob no aplicativo se comuniquem com o Armazenamento de Blobs em execução dentro do contêiner do Docker gerenciado por Testcontainers. Essa configuração define automaticamente um AzureStorageBlobConnectionDetails bean, que a configuração automática do Armazenamento de Blobs usa para substituir as propriedades de configuração relacionadas à conexão.
@SpringBootTest(classes = StorageQueueTestcontainersTest.class)
@Testcontainers
@TestPropertySource(properties = "spring.cloud.azure.storage.queue.queue-name=devstoreaccount1/tc-queue")
@ExtendWith(SpringExtension.class)
@ImportAutoConfiguration(classes = { AzureGlobalPropertiesAutoConfiguration.class, AzureStorageQueueAutoConfiguration.class})
public class StorageQueueTestcontainersTest {
@Container
@ServiceConnection
private static final GenericContainer<?> AZURITE_CONTAINER = new GenericContainer<>(
"mcr.microsoft.com/azure-storage/azurite:latest")
.withExposedPorts(10001)
.withCommand("azurite-queue", "--queueHost", "0.0.0.0", "--skipApiVersionCheck");
@Autowired
private QueueClient queueClient;
@BeforeAll
public static void setup() {
AZURITE_CONTAINER.start();
}
@Test
public void test() {
String message = "Hello World!";
this.queueClient.create();
this.queueClient.sendMessage(message);
assertThat(this.queueClient.receiveMessage().getBody().toString()).isEqualTo(message);
}
}
Com @ServiceConnection, essa configuração permite que os feijões relacionados à fila no aplicativo se comuniquem com o Armazenamento de Filas em execução dentro do contêiner do Docker gerenciado por Testcontainers. Essa configuração define automaticamente um AzureStorageQueueConnectionDetails bean, que a configuração automática do Armazenamento de Filas usa para substituir as propriedades de configuração relacionadas à conexão.
@SpringJUnitConfig
@TestPropertySource(properties = { "spring.cloud.azure.eventhubs.event-hub-name=eh1",
"spring.cloud.azure.eventhubs.producer.event-hub-name=eh1" })
@Testcontainers
class EventHubsTestContainerTest {
private static final Network NETWORK = Network.newNetwork();
private static final AzuriteContainer AZURITE = new AzuriteContainer(
"mcr.microsoft.com/azure-storage/azurite:latest")
.withNetwork(NETWORK)
.withNetworkAliases("azurite");
@Container
@ServiceConnection
private static final EventHubsEmulatorContainer EVENT_HUBS = new EventHubsEmulatorContainer(
"mcr.microsoft.com/azure-messaging/eventhubs-emulator:latest")
.acceptLicense()
.withCopyFileToContainer(MountableFile.forClasspathResource("Config.json"),
"/Eventhubs_Emulator/ConfigFiles/Config.json")
.withNetwork(NETWORK)
.withAzuriteContainer(AZURITE);
@Autowired
private AzureEventHubsConnectionDetails connectionDetails;
@Autowired
private EventHubProducerClient producerClient;
@Test
void connectionDetailsShouldBeProvidedByFactory() {
assertThat(connectionDetails).isNotNull();
assertThat(connectionDetails.getConnectionString())
.isNotBlank()
.startsWith("Endpoint=sb://");
}
@Test
void producerClientCanSendMessage() {
// Wait for Event Hubs emulator to be fully ready and event hub entity to be available
waitAtMost(Duration.ofSeconds(120)).pollInterval(Duration.ofSeconds(2)).untilAsserted(() -> {
EventData event = new EventData("Hello World!");
this.producerClient.send(Collections.singletonList(event));
});
}
@Configuration(proxyBeanMethods = false)
@ImportAutoConfiguration(classes = {AzureGlobalPropertiesAutoConfiguration.class,
AzureEventHubsAutoConfiguration.class})
static class Config {
}
}
Com @ServiceConnectionisso, essa configuração permite que os feijões relacionados no aplicativo se comuniquem com os Hubs de Eventos em execução dentro do contêiner do Docker gerenciado por Testcontainers. Essa configuração define automaticamente um AzureEventHubsConnectionDetails bean, que a configuração automática dos Hubs de Eventos usa para substituir as propriedades de configuração relacionadas à conexão.
@SpringJUnitConfig
@TestPropertySource(properties = {
"spring.cloud.function.definition=consume;supply",
"spring.cloud.stream.bindings.consume-in-0.destination=eh1",
"spring.cloud.stream.bindings.consume-in-0.group=$Default",
"spring.cloud.stream.bindings.supply-out-0.destination=eh1",
"spring.cloud.stream.eventhubs.bindings.consume-in-0.consumer.checkpoint.mode=MANUAL",
"spring.cloud.stream.poller.fixed-delay=1000",
"spring.cloud.stream.poller.initial-delay=0"})
@Testcontainers
class EventHubsTestContainerTest {
private static final Network NETWORK = Network.newNetwork();
private static final AzuriteContainer AZURITE = new AzuriteContainer(
"mcr.microsoft.com/azure-storage/azurite:latest")
.withCommand("azurite", "--blobHost", "0.0.0.0", "--queueHost", "0.0.0.0", "--tableHost", "0.0.0.0",
"--skipApiVersionCheck")
.withNetwork(NETWORK)
.withNetworkAliases("azurite");
@Container
@ServiceConnection
private static final EventHubsEmulatorContainer EVENT_HUBS = new EventHubsEmulatorContainer(
"mcr.microsoft.com/azure-messaging/eventhubs-emulator:latest")
.acceptLicense()
.withCopyFileToContainer(MountableFile.forClasspathResource("Config.json"),
"/Eventhubs_Emulator/ConfigFiles/Config.json")
.withNetwork(NETWORK)
.withAzuriteContainer(AZURITE);
private static final Logger LOGGER = LoggerFactory.getLogger(EventHubsTestContainerTest.class);
private static final Set<String> RECEIVED_MESSAGES = ConcurrentHashMap.newKeySet();
private static final AtomicInteger MESSAGE_SEQUENCE = new AtomicInteger(0);
@Test
void supplierAndConsumerShouldWorkThroughEventHubs() {
waitAtMost(Duration.ofSeconds(120))
.pollDelay(Duration.ofSeconds(2))
.pollInterval(Duration.ofSeconds(2))
.untilAsserted(() -> {
assertThat(RECEIVED_MESSAGES).isNotEmpty();
LOGGER.info("✓ Test passed - Consumer received {} message(s)", RECEIVED_MESSAGES.size());
});
}
@Configuration(proxyBeanMethods = false)
@EnableAutoConfiguration
@ImportAutoConfiguration(classes = {
AzureGlobalPropertiesAutoConfiguration.class,
AzureEventHubsAutoConfiguration.class,
AzureEventHubsMessagingAutoConfiguration.class})
static class Config {
private static final String CHECKPOINT_CONTAINER_NAME = "eventhubs-checkpoint";
@Bean
public BlobCheckpointStore blobCheckpointStore() {
BlobServiceAsyncClient blobServiceAsyncClient = new BlobServiceClientBuilder()
.connectionString(AZURITE.getConnectionString())
.serviceVersion(BlobServiceVersion.V2025_01_05)
.buildAsyncClient();
BlobContainerAsyncClient containerAsyncClient = blobServiceAsyncClient
.getBlobContainerAsyncClient(CHECKPOINT_CONTAINER_NAME);
if (Boolean.FALSE.equals(containerAsyncClient.exists().block(Duration.ofSeconds(3)))) {
containerAsyncClient.create().block(Duration.ofSeconds(3));
}
return new BlobCheckpointStore(containerAsyncClient);
}
@Bean
public Supplier<Message<String>> supply() {
return () -> {
int sequence = MESSAGE_SEQUENCE.getAndIncrement();
String payload = "Hello world, " + sequence;
LOGGER.info("[Supplier] Invoked - message sequence: {}", sequence);
return MessageBuilder.withPayload(payload).build();
};
}
@Bean
public Consumer<Message<String>> consume() {
return message -> {
String payload = message.getPayload();
RECEIVED_MESSAGES.add(payload);
LOGGER.info("[Consumer] Received message: {}", payload);
Checkpointer checkpointer = (Checkpointer) message.getHeaders().get(CHECKPOINTER);
if (checkpointer != null) {
checkpointer.success()
.doOnSuccess(s -> LOGGER.info("[Consumer] Message checkpointed"))
.doOnError(e -> LOGGER.error("[Consumer] Checkpoint failed", e))
.block();
}
};
}
}
}
Com @ServiceConnectionisso, essa configuração permite que os feijões relacionados no aplicativo se comuniquem com os Hubs de Eventos em execução dentro do contêiner do Docker gerenciado por Testcontainers. Essa configuração define automaticamente um AzureEventHubsConnectionDetails bean, que a configuração automática dos Hubs de Eventos usa para substituir as propriedades de configuração relacionadas à conexão.
@SpringJUnitConfig
@TestPropertySource(properties = { "spring.cloud.azure.servicebus.entity-name=queue.1",
"spring.cloud.azure.servicebus.entity-type=queue" })
@Testcontainers
class ServiceBusTestContainerTest {
private static final Network NETWORK = Network.newNetwork();
private static final MSSQLServerContainer<?> SQLSERVER = new MSSQLServerContainer<>(
"mcr.microsoft.com/mssql/server:2022-CU14-ubuntu-22.04")
.acceptLicense()
.withNetwork(NETWORK)
.withNetworkAliases("sqlserver");
@Container
@ServiceConnection
private static final ServiceBusEmulatorContainer SERVICE_BUS = new ServiceBusEmulatorContainer(
"mcr.microsoft.com/azure-messaging/servicebus-emulator:latest")
.acceptLicense()
.withCopyFileToContainer(MountableFile.forClasspathResource("Config.json"),
"/ServiceBus_Emulator/ConfigFiles/Config.json")
.withNetwork(NETWORK)
.withMsSqlServerContainer(SQLSERVER);
@Autowired
private AzureServiceBusConnectionDetails connectionDetails;
@Autowired
private ServiceBusSenderClient senderClient;
@Autowired
private ServiceBusTemplate serviceBusTemplate;
@Test
void connectionDetailsShouldBeProvidedByFactory() {
assertThat(connectionDetails).isNotNull();
assertThat(connectionDetails.getConnectionString())
.isNotBlank()
.startsWith("Endpoint=sb://");
}
@Test
void senderClientCanSendMessage() {
// Wait for Service Bus emulator to be fully ready and queue entity to be available
waitAtMost(Duration.ofSeconds(120)).pollInterval(Duration.ofSeconds(2)).untilAsserted(() -> {
this.senderClient.sendMessage(new ServiceBusMessage("Hello World!"));
});
waitAtMost(Duration.ofSeconds(30)).untilAsserted(() -> {
assertThat(Config.MESSAGES).contains("Hello World!");
});
}
@Test
void serviceBusTemplateCanSendMessage() {
// Wait for Service Bus emulator to be fully ready and queue entity to be available
waitAtMost(Duration.ofSeconds(120)).pollInterval(Duration.ofSeconds(2)).untilAsserted(() -> {
this.serviceBusTemplate.sendAsync("queue.1",
MessageBuilder.withPayload("Hello from ServiceBusTemplate!").build()).block(Duration.ofSeconds(10));
});
waitAtMost(Duration.ofSeconds(30)).untilAsserted(() -> {
assertThat(Config.MESSAGES).contains("Hello from ServiceBusTemplate!");
});
}
@Configuration(proxyBeanMethods = false)
@ImportAutoConfiguration(classes = {AzureGlobalPropertiesAutoConfiguration.class,
AzureServiceBusAutoConfiguration.class,
AzureServiceBusMessagingAutoConfiguration.class})
static class Config {
private static final Set<String> MESSAGES = ConcurrentHashMap.newKeySet();
@Bean
ServiceBusRecordMessageListener processMessage() {
return context -> {
MESSAGES.add(context.getMessage().getBody().toString());
};
}
@Bean
ServiceBusErrorHandler errorHandler() {
// No-op error handler for tests: acknowledge errors without affecting test execution.
return (context) -> {
};
}
}
}
Com @ServiceConnectionisso, essa configuração permite que os feijões relacionados no aplicativo se comuniquem com o Barramento de Serviço em execução dentro do contêiner do Docker gerenciado por Testcontainers. Essa configuração define automaticamente um AzureServiceBusConnectionDetails bean, que a configuração automática do Barramento de Serviço usa para substituir as propriedades de configuração relacionadas à conexão.
@SpringJUnitConfig
@TestPropertySource(properties = {
"spring.cloud.function.definition=consume;supply",
"spring.cloud.stream.bindings.consume-in-0.destination=queue.1",
"spring.cloud.stream.bindings.supply-out-0.destination=queue.1",
"spring.cloud.stream.servicebus.bindings.consume-in-0.consumer.auto-complete=false",
"spring.cloud.stream.servicebus.bindings.supply-out-0.producer.entity-type=queue",
"spring.cloud.stream.poller.fixed-delay=1000",
"spring.cloud.stream.poller.initial-delay=0"})
@Testcontainers
class ServiceBusTestContainerTest {
private static final Network NETWORK = Network.newNetwork();
private static final MSSQLServerContainer<?> SQLSERVER = new MSSQLServerContainer<>(
"mcr.microsoft.com/mssql/server:2022-CU14-ubuntu-22.04")
.acceptLicense()
.withNetwork(NETWORK)
.withNetworkAliases("sqlserver");
@Container
@ServiceConnection
private static final ServiceBusEmulatorContainer SERVICE_BUS = new ServiceBusEmulatorContainer(
"mcr.microsoft.com/azure-messaging/servicebus-emulator:latest")
.acceptLicense()
.withCopyFileToContainer(MountableFile.forClasspathResource("Config.json"),
"/ServiceBus_Emulator/ConfigFiles/Config.json")
.withNetwork(NETWORK)
.withMsSqlServerContainer(SQLSERVER);
private static final Logger LOGGER = LoggerFactory.getLogger(ServiceBusTestContainerTest.class);
private static final Set<String> RECEIVED_MESSAGES = ConcurrentHashMap.newKeySet();
private static final AtomicInteger MESSAGE_SEQUENCE = new AtomicInteger(0);
@Test
void supplierAndConsumerShouldWorkThroughServiceBusQueue() {
waitAtMost(Duration.ofSeconds(60))
.pollDelay(Duration.ofSeconds(2))
.untilAsserted(() -> {
assertThat(RECEIVED_MESSAGES).isNotEmpty();
LOGGER.info("✓ Test passed - Consumer received {} message(s)", RECEIVED_MESSAGES.size());
});
}
@Configuration(proxyBeanMethods = false)
@EnableAutoConfiguration
@ImportAutoConfiguration(classes = {
AzureGlobalPropertiesAutoConfiguration.class,
AzureServiceBusAutoConfiguration.class,
AzureServiceBusMessagingAutoConfiguration.class})
static class Config {
@Bean
public Supplier<Message<String>> supply() {
return () -> {
int sequence = MESSAGE_SEQUENCE.getAndIncrement();
String payload = "Hello world, " + sequence;
LOGGER.info("[Supplier] Invoked - message sequence: {}", sequence);
return MessageBuilder.withPayload(payload).build();
};
}
@Bean
public Consumer<Message<String>> consume() {
return message -> {
String payload = message.getPayload();
RECEIVED_MESSAGES.add(payload);
LOGGER.info("[Consumer] Received message: {}", payload);
Checkpointer checkpointer = (Checkpointer) message.getHeaders().get(CHECKPOINTER);
if (checkpointer != null) {
checkpointer.success()
.doOnSuccess(s -> LOGGER.info("[Consumer] Message checkpointed"))
.doOnError(e -> LOGGER.error("[Consumer] Checkpoint failed", e))
.block();
}
};
}
}
}
Com @ServiceConnectionisso, essa configuração permite que os feijões relacionados no aplicativo se comuniquem com o Barramento de Serviço em execução dentro do contêiner do Docker gerenciado por Testcontainers. Essa configuração define automaticamente um AzureServiceBusConnectionDetails bean, que a configuração automática do Barramento de Serviço usa para substituir as propriedades de configuração relacionadas à conexão.