HiveMQ Testcontainer 2.0.0 Released
About HiveMQ Testcontainer 2.0.0
Automated integration testing of MQTT applications is a challenging task since it requires you to simulate or set up an MQTT deployment of some kind. When testing MQTT client applications, you need a deployed MQTT broker. Sharing the deployment across multiple tests can be troublesome. Shared deployments can cause unwanted interferences between tests that produce unexpected results and flaky tests. Integration-testing custom HiveMQ extensions can be even more difficult since the extension must be packaged, deployed, and started automatically. While developing extensions such as our Enterprise Security Extension, HiveMQ Extension for Kafka and the HiveMQ Bridge Extension we frequently encountered this issue. To eliminate this pain point, we developed the official HiveMQ Testcontainer, whose 2.0.0 release we proudly announce today.
The HiveMQ Testcontainer is a Java library that gives you the right tools for automated JUnit 4 and JUnit 5 testing of MQTT client applications and custom HiveMQ extensions. Use the Testcontainer to start up customizable HiveMQ docker containers that are exclusive to each integration test. On top of that, the process of packaging and deploying HiveMQ extensions directly from source can be automated.
The 2.0.0 release of the HiveMQ Testcontainer brings you the following benefits:
Streamlined debugging of HiveMQ extensions
Enhanced the accessibility of the Control Center of HiveMQs that are running inside the container
Improved API
See the project on GitHub.
The library is available on Maven Central for JUnit 4 and JUnit 5.
Add to your project
To add the HiveMQ Testcontainer to your project, add these dependencies to your build.gradle.kts
testImplementation "com.hivemq:hivemq-testcontainer-junit5:2.0.0"
testImplementation "org.junit.jupiter:junit-jupiter-engine:5.6.1"
testRuntimeOnly "org.junit.jupiter:junit-jupiter-api:5.6.1"
Debug your custom HiveMQ extension
This tutorial shows you how to debug your custom HiveMQ extension with IntelliJ:
Access the HiveMQ Control Center
To access the HiveMQ Control Center do the following:
Create a new
HiveMQTestContainerExtension
, make sure to use aHiveMQ Enterprise
image, because the Control Center is not available in theHiveMQ Community Edition
.Register the
Extension
with JUnit 5use
withControlCenter()
to indicate that the Control Center address should be displayed
public class TestMqttIT {
@RegisterExtension // 2
HiveMQTestContainerExtension rule = new HiveMQTestContainerExtension(DockerImageName.parse("hivemq/hivemq4").withTag("4.7.0"))) // 1
.withControlCenter() // 3
@Test
void test_mqtt() throws InterruptedException {
// ...
}
}
After the HiveMQ Testcontainer has started successfully, the Control Center address is logged:
2021-09-23 07:51:32,793 INFO - Started HiveMQ in 9775ms
2021-09-23 09:51:32,788 INFO - Container hivemq/hivemq4:4.7.0 started in PT16.67462S
2021-09-23 09:51:32,788 INFO - The HiveMQ Control Center is reachable under: http://localhost:62261
Test your MQTT application
Testing your MQTT application can look something like this:
Create a new
HiveMQTestContainerExtension
Register the
Extension
with JUnit 5Connect your MQTT clients to the HiveMQ instance that is running inside the container. Use the port that you retrieve from the rule with the
getMqttPort()
method.Assert the expected behavior.
public class TestMqttIT {
@RegisterExtension // 2
HiveMQTestContainerExtension container = new HiveMQTestContainerExtension(); // 1
@Test
void test_mqtt() throws InterruptedException {
final Mqtt5BlockingClient publisher = Mqtt5Client.builder()
.serverPort(container.getMqttPort()) // 3
.identifier("publisher")
.buildBlocking();
publisher.connect();
final Mqtt5BlockingClient subscriber = Mqtt5Client.builder()
.serverPort(container.getMqttPort()) // 3
.identifier("subscriber")
.buildBlocking();
subscriber.connect();
subscriber.subscribeWith().topicFilter("topic/test").send();
publisher.publishWith()
.topic("topic/test")
.payload("Hello World!".getBytes()).send();
final Mqtt5Publish receive = subscriber.publishes(MqttGlobalPublishFilter.ALL).receive();
assertNotNull(receive); // 4
assertEquals("Hello World!", new String(receive.getPayloadAsBytes())); // 4
}
}
Test your custom HiveMQ extension
The HiveMQ testcontainer in conjunction with the HiveMQ Extension Gradle Plugin provide a clean way to integration test HiveMQ Extension. The HiveMQ Hello World Extension shows you in detail how this can be setup.
In this example the extension to test provides a custom PublishInboundInterceptor
which replaces every incoming publish payload with the string "modified"
. It looks like this:
public class MyExtension implements ExtensionMain {
@Override
public void extensionStart(@NotNull ExtensionStartInput extensionStartInput, @NotNull ExtensionStartOutput extensionStartOutput) {
final PublishInboundInterceptor publishInboundInterceptor = (publishInboundInput, publishInboundOutput) -> {
publishInboundOutput.getPublishPacket().setPayload(ByteBuffer.wrap("modified".getBytes(StandardCharsets.UTF_8)));
};
final ClientInitializer clientInitializer = (initializerInput, clientContext) -> {
clientContext.addPublishInboundInterceptor(publishInboundInterceptor);
};
Services.initializerRegistry().setClientInitializer(clientInitializer);
}
...
}
To actually test the HiveMQ extension, we do the following:
Create a new
HiveMQTestContainerExtension
Register the
Extension
with JUnit 5Add the HiveMQ Extension to the
HiveMQTestContainerExtension
Connect your MQTT clients to the HiveMQ instance that is running inside the container. Use the port that you retrieve from the rule with the
getMqttPort()
method.Assert the expected behavior.
public class TestMqttIT {
@RegisterExtension // 2
HiveMQTestContainerExtension rule = new HiveMQTestContainerExtension() // 1
.withExtension(MountableFile.forHostPath("build/hivemq-extension-test/hivemq-hello-world-extension")); // 3
@Test
void test_mqtt() throws InterruptedException {
final Mqtt5BlockingClient publisher = Mqtt5Client.builder()
.serverPort(rule.getMqttPort()) // 4
.identifier("publisher")
.buildBlocking();
publisher.connect();
final Mqtt5BlockingClient subscriber = Mqtt5Client.builder()
.serverPort(rule.getMqttPort()) // 4
.identifier("subscriber")
.buildBlocking();
subscriber.connect();
subscriber.subscribeWith().topicFilter("topic/test").send();
publisher.publishWith()
.topic("topic/test")
.payload("Hello World!".getBytes()).send();
final Mqtt5Publish receive = subscriber.publishes(MqttGlobalPublishFilter.ALL).receive();
assertNotNull(receive); // 5
assertEquals("modified", new String(receive.getPayloadAsBytes())); // 5
}
}
Conclusion
Using the HiveMQ Testcontainer makes the process of automatic testing of MQTT client applications and custom HiveMQ extensions easier and more robust.
HiveMQ Team
The HiveMQ team loves writing about MQTT, Sparkplug, Industrial IoT, protocols, how to deploy our platform, and more. We focus on industries ranging from energy, to transportation and logistics, to automotive manufacturing. Our experts are here to help, contact us with any questions.