Skip to content

HiveMQ Community Edition in a test container

by HiveMQ Team
3 min read

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.

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.

Related content:

HiveMQ logo
Review HiveMQ on G2