HiveMQ Testcontainer Released
HiveMQ Testcontainers
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 or the HiveMQ Extension for Kafka, we frequently encountered this issue. To eliminate this pain point, we developed the official HiveMQ Testcontaier, whose 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.
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 pom.xml:
<dependency>
<groupId>com.hivemq</groupId>
<artifactId>hivemq-testcontainer-junit4</artifactId>
<version>1.0.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13</version>
<scope>test</scope>
</dependency>
Test your MQTT application
Testing your MQTT application can look something like this:
Create a new
HiveMQTestContainerRuleRegister the
Rulewith JUnit 4Connect 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 {
@Rule // 2
HiveMQTestContainerRule rule = new HiveMQTestContainerRule(); // 1
@Test
void test_mqtt() throws InterruptedException {
final Mqtt5BlockingClient publisher = Mqtt5Client.builder()
.serverPort(rule.getMqttPort()) // 3
.identifier("publisher")
.buildBlocking();
publisher.connect();
final Mqtt5BlockingClient subscriber = Mqtt5Client.builder()
.serverPort(rule.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
To test your custom HiveMQ extension, you need to have the HiveMQ Extension SDK on your classpath. If the SDK is not already there, add it to your pom.xml:
<dependency>
<groupId>com.hivemq</groupId>
<artifactId>hivemq-extension-sdk</artifactId>
<version>4.3.0</version>
</dependency> 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
HiveMQTestContainerRuleRegister the
Rulewith JUnit 4Add the HiveMQ Extension to the
HiveMQTestContainerRuleby providing itsid,name,version,priority,start-priorityandmain class`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 {
@Rule // 2
HiveMQTestContainerRule rule = new HiveMQTestContainerRule() // 1
.withExtension(HiveMQExtension.builder()
.id("extension-1")
.name("my-extension")
.version("1.0")
.mainClass(MyExtension.class).build()) // 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
}
} Using JUnit5
If you want to use JUnit 5, add these dependencies to your pom.xml:
<dependency>
<groupId>com.hivemq</groupId>
<artifactId>hivemq-testcontainer-junit5</artifactId>
<version>1.0.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<version>5.6.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<version>5.6.1</version>
<scope>test</scope>
</dependency> The API is almost identical. Simply replace @Rule with @RegisterExtension and HiveMQTestContainerRule with HiveMQTestContainerExtension:
@RegisterExtension
HiveMQTestContainerExtension extension = new HiveMQTestContainerExtension()
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
Team HiveMQ shares deep expertise in MQTT, Industrial AI, IoT data streaming, Unified Namespace (UNS), and Industrial IoT protocols. Our blogs explore real-world challenges, practical deployment guidance, and best practices for building modern, reliable, and a secure data backbone on the HiveMQ platform, along with thought leadership shaping the future of the connected world.
We’re on a mission to build the Industrial AI Platform that transforms industrial data into real-time intelligence, actionable insights, and measurable business outcomes.
Our experts are here to support your journey. Have questions? We’re happy to help. Contact us.
