HiveMQ Community Edition in a test container
Testing your MQTT client application with a HiveMQ Community Edition test container
Testing your MQTT client application is not a simple task, since you have to have a running MQTT broker in your testing environment. Sharing your broker deployment between multiple tests can lead to unwanted interferences, unexpected behaviour and flaky tests. The solution is to start a containerized HiveMQ broker that you use exclusively for each test and destroy afterwards. This blog post shows you how to do this automatically in JUnit 4 and JUnit 5 with the help of the Testcontainers Project. If you are new to MQTT protocol, I recommend you to read MQTT Essentials here.
JUnit 4
First, add the following dependencies to your classpath:
Next, add this class that extends the JUnit 4 TestWatcher
to your testing environment:
public class HiveMQTestContainerRule extends TestWatcher {
private static final @NotNull String HIVEMQ_CE_IMAGE = "hivemq/hivemq-ce";
private static final @NotNull String HIVEMQ_CE_VERSION = "latest";
public static final int MQTT_PORT = 1883;
private final @NotNull GenericContainer container;
public HiveMQTestContainerRule() {
container = new GenericContainer(HIVEMQ_CE_IMAGE + ":" + HIVEMQ_CE_VERSION);
container.withExposedPorts(MQTT_PORT);
final LogMessageWaitStrategy waitStrategy = new LogMessageWaitStrategy();
waitStrategy.withRegEx(".*Started HiveMQ in.*");
container.waitingFor(waitStrategy);
}
@Override
protected void starting(final @NotNull Description description) {
container.start();
}
@Override
protected void finished(final @NotNull Description description) {
container.stop();
}
public int getMqttPort() {
return container.getMappedPort(MQTT_PORT);
}
}
You can use the @Rule
annotation to add the HiveMQTestContainerRule
to every JUnit 4 test class that you want. The MQTT port can be retrieved with the getMqttPort
method.
public class MqttClientTestWithContainerRule {
@Rule
final public @NotNull HiveMQTestContainerRule rule = new HiveMQTestContainerRule();
@Test
public void test_mqtt() {
final Mqtt5BlockingClient client = Mqtt5Client.builder()
.serverPort(rule.getMqttPort())
.buildBlocking();
client.connect();
client.disconnect();
}
}
JUnit 5
First, add the following dependencies to your classpath:
Next, add this class that implements the JUnit5 BeforeEachCallback
and AfterEachCallback
to your testing environment:
public class HiveMQTestContainerExtension implements BeforeEachCallback, AfterEachCallback {
private static final @NotNull String HIVEMQ_CE_IMAGE = "hivemq/hivemq-ce";
private static final @NotNull String HIVEMQ_CE_VERSION = "latest";
public static final int MQTT_PORT = 1883;
private final @NotNull GenericContainer container;
public HiveMQTestContainerExtension() {
container = new GenericContainer(HIVEMQ_CE_IMAGE + ":" + HIVEMQ_CE_VERSION);
container.withExposedPorts(MQTT_PORT);
final LogMessageWaitStrategy waitStrategy = new LogMessageWaitStrategy();
waitStrategy.withRegEx(".*Started HiveMQ in.*");
container.waitingFor(waitStrategy);
}
@Override
public void beforeEach(final @NotNull ExtensionContext context) throws Exception {
container.start();
}
@Override
public void afterEach(final @NotNull ExtensionContext context) throws Exception {
container.stop();
}
public int getMqttPort() {
return container.getMappedPort(MQTT_PORT);
}
}
You can use the @RegisterExtension
annotation to add the HiveMQTestContainerExtension
to every JUnit 5 test class as desired. The MQTT port can be retrieved with the getMqttPort
method.
public class MqttClientTestWithContainerExtension {
@RegisterExtension
public final @NotNull HiveMQTestContainerExtension extension = new HiveMQTestContainerExtension();
@Test
void test_mqtt() {
final Mqtt5BlockingClient client = Mqtt5Client.builder()
.serverPort(extension.getMqttPort())
.buildBlocking();
client.connect();
client.disconnect();
}
}
Conclusion
These methods make it very easy to automate the process of starting a fresh MQTT broker. The development and testing process for your client applications becomes more robust when you use use a containerized, isolated, and exclusive broker for every test.
![Yannick Weber](https://s3.amazonaws.com/a.storyblok.com/f/243938/192x258/7456567b43/portrait-yannick-weber.png)
Yannick Weber
Yannick is a Senior Software Engineer and one of the core members of HiveMQ's product development team. He has a strong interest in messaging technologies and is focusing on quality development of HiveMQ's many tools and extensions. In addition, he is the maintainer of the HiveMQ module in the testcontainers-java project.