Die Bedeutung von Integrationstests in der Welt der Softwareentwicklung kann nicht genug betont werden. Insbesondere in der Programmiersprache Go/Golang, wenn es darum geht, eine nahtlose Anbindung an Apache Kafka mit der conluent-kafka-go Bibliothek zu gewährleisten.
In diesem Artikel wird gezeigt wie man mit Hilfe eines von der conluent-kafka-go Bibliothek zur Verfügung gestellten Mock-Clusters Integrationstests für Apache Kafka schreiben kann. Diese können ohne Probleme in einer Build-Pipeline ausgeführt werden, ohne dass eine Apache Kafka Instanz benötigt wird.
Folgende Ziele sollen beim Testen erreicht werden:
Tests sollen in einer CI/CD-Pipeline “autark” ausgeführt werden können. Mehrere Tests sollen parallel ausgeführt werden können ohne dass diese sich gegenseitig beeinflussen.
Wenig Ressourcenbedarf beim Testablauf.
Schnelle Durchlaufgeschwindigkeit.
In vielen geschäftskritischen Anwendungen wird Apache-Kafka für die Kommunikation bzw. den Austausch von Datenströmen zwischen mehreren unabhängigen Microservices eingesetzt. Kern eines Kafka-Clusters sind sogenannte Message-Broker, die diese Daten speichern und entsprechend an Konsumenten oder Consumer weitergeben. Nachrichten-Producer erzeugen die Datenströme in Form von Nachrichten, den sogenannten Messages.
Das Messaging-Pattern beschreibt z. B. die Einsatz eines Message-Brokers innerhalb von Anwendungen für die asynchrone Kommunikation.
Kafka besitzt für die Kommunikation eine API, die nicht nur von Java (Apache-Kafka ist selbst in Java implementiert) aus, sondern auch von vielen weiteren Programmiersprachen angesprochen werden kann. Der Zugriff auf Apache Kafka mittels Go erfolgt analog über eine entsprechende Client-Bibliothek. Mehrere Varianten stehen hier zur Verfügung und bieten unterschiedliche Vor- und Nachteile:
In diesem Artikel wird mit der conluent-kafka-go Bibliothek gearbeitet, die von Confluent Inc. entwickelt wurde und als Open-Source bei GitHub zur Verfügung steht. Sie basiert auf der librdkafka C-Bibliothek, die ebenfalls in anderen Programmiersprachen als Basis für eine Anbindung an Apache Kafka eingesetzt wird.
Der große Vorteil eines Einsatz liegt sicher in der Stabilität und Reife der Implementierung. Confluent ist das Unternehmen, das Kafka unterstützt und erweitert. Die Verwendung der von Confluent bereitgestellten Client-Bibliothek gewährleistet eine hohe Qualität und Zuverlässigkeit, da sie direkt von den Experten entwickelt und gewartet wird.
Zusätzlich ist die Bibliothek darauf ausgerichtet, eine hohe Leistung zu bieten und effizient mit Kafka-Clustern kommunizieren.
Neben den wichtigen Punkten für einen effektiven Einsatz in der Produktion bietet die Bibliothek ebenfalls einen sogenannten Mock-Cluster, der speziell für den Einsatz in Integrationstests entwickelt wurde.
Wenn eine leistungsstarke Messaging-Lösung für Go-Anwendungen benötigt wird, ist die Kombintation aus Apache Kafka und dieser Bibliothek sicher eine gute Wahl.
Für das Beispiel wird davon ausgegangen, dass bereits zwei Funktionen für das
Senden (Produce
) und Empfangen (Consumer
) von Nachrichten über Kafka
implementiert sind. Beide Funktionen erhalten den string der BootstrapServers
als Parameter übergeben.
An dieser Stelle kommt nun der Mock-Server zum Einsatz. Dieser lässt sich mit folgendem Aufruf starten:
cluster, err := kafka.NewMockCluster(1)
Anschließend kann man den dynamischen Port, der für die Kommunikation verwendet wird, auslesen und als Parameter für Consumer und Producer nutzen: Z. B. so:
Produce(cluster.BootstrapServers(), testMessage)
In einem gesamten Beispiel lässt sich das wie Folgt verwenden:
package kafkaintegrationtest
import (
"github.com/confluentinc/confluent-kafka-go/v2/kafka"
"testing"
)
func TestKafka(t *testing.T) {
//given
testMessage := "Hello World"
cluster, err := kafka.NewMockCluster(1)
if err != nil {
t.Errorf("could not start cluster: %v", err)
return
}
//when
go func() {
err := Produce(cluster.BootstrapServers(), testMessage)
if err != nil {
t.Errorf("could not produce message: %v", err)
return
}
}()
message, err := Consumer(cluster.BootstrapServers())
if err != nil {
t.Errorf("could not consume message: %v", err)
return
}
//then
if message != testMessage {
t.Errorf("wrong message received: %s", message)
}
}
Mit diesem Ansatz lassen sich leicht weitere Tests schreiben, die eventuell auch besser wie in diesem Beispiel synchronisiert sind.
Der Mock-Server bietet noch weitere Möglichkeiten. So können auch Fehlerfälle simuliert werden. Die komplette API findet man bei GitHub.
Mit Hilfe des Mock-Servers der Bibliothek lassen sich praxisnahe Integrationstests implementieren, die möglichst nahe an der Produktionsumgebung sind, da sie über Remote-Schnittstellen kommunizieren und die echte Implementierung nutzen.
Zum Testen wird in diesem Beispiel kein eigener Kafka Server benötigt und trotzdem wird über die “echten” Schnittstellen kommuniziert.
Das komplette Beispiel kann auch in GitHub gefunden werden.
16.11.2023
Der praktische Soforteinstieg für Developer und Softwarearchitekten, die direkt mit Go produktiv werden wollen.
zur Buchseite beim Rheinwerk Verlag Rheinwerk Computing, ISBN 978-3-8362-7559-0 (als PDF, EPUB, MOBI und Papier)
Source Fellows GmbH
Lerchenstraße 31
72762 Reutlingen
Telefon: (0049) 07121 6969 802
E-Mail: info@source-fellows.com