HiveMQ Testcontainer 2.0.0 Released

HiveMQ Testcontainer 2.0.0 Released

author Yannick Weber

Written by Yannick Weber

Category: HiveMQ Testing Test Container MQTT Client

Published: September 22, 2021


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:

1
2
3
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:

  1. Create a new HiveMQTestContainerExtension, make sure to use a HiveMQ Enterprise image, because the Control Center is not available in the HiveMQ Community Edition.
  2. Register the Extension with JUnit 5
  3. use withControlCenter() to indicate that the Control Center address should be displayed
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
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:

1
2
3
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:

  1. Create a new HiveMQTestContainerExtension
  2. Register the Extension with JUnit 5
  3. 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.
  4. Assert the expected behavior.
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
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:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
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:

  1. Create a new HiveMQTestContainerExtension
  2. Register the Extension with JUnit 5
  3. Add the HiveMQ Extension to the HiveMQTestContainerExtension
  4. 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.
  5. Assert the expected behavior.
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
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.

author Yannick Weber

About Yannick Weber

Yannick is a Senior Software Engineer and one of the core members of HiveMQ’s product development team. He 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.

mail icon Contact Yannick
newer posts Monitoring Plant Floor Data Using MQTT, HiveMQ Cloud, InfluxDB, Grafana, & Schneider IIoT Gateway
New GitHub example repositories older posts