NBomber ist ein leichtgewichtiges und flexibles Framework zum Erstellen und Durchführen von Lasttests. Dank der Fluent-API und den bestehenden Testbausteinen können aussagekräftige Tests ohne viel Aufwand erstellt werden.
Das Basisframework ist in F# implementiert und ist open-source. Testfälle werden in C# oder F# geschrieben. NBomber stellt vorgefertigte Testbausteine zur Verfügung. Diese können im Code beliebig mit eigener Logik ergänzt werden und ermöglichen das Testen von verschiedensten Applikationen – z. B. mittels API-Aufrufen, Datenbankabfragen oder via Message Broker. Die dadurch entstehende Flexibilität bietet einen grossen Vorteil gegenüber eher geschlossenen UI-basierten Werkzeugen wie beispielsweise Appache JMeter.
Unter einem Lasttest versteht man einen Softwaretest, der eine in der Regel sehr hohe Last auf dem zu testenden System erzeugt und dessen Verhalten untersucht. Dazu kann eine Simulation eingesetzt werden. Wikipedia
Bezüglich dem Testziel wird zwischen Last– und Stresstest unterschieden:
Nach: Microsoft Docs
Zum Starten mit dem Lasttesting werden NBomber sowie die auf NBomber basierenden Erweiterungen und Plugins als Nuget-Pakete ins .NET-Projekt integriert:
Das Schreiben von Testfällen mit NBomber basiert auf drei Bausteinen:
Ein Step ist die kleinste logische Einheit. Ein Step ist eine Aktion, welche wir auf dem zu testenden System ausführen wollen. Er entspricht einem Methodenaufruf in C# oder F#. Konkrete Aufrufe oder Abhängigkeiten zu Protokollen und Frameworks sind so von NBomber abstrahiert. Dadurch ergibt sich eine maximale Flexibilität in der Gestaltung der Lasttests. Zur effizienten Testerstellung gibt’s von NBomber mehrere Plugins um Aktionen zu programmieren (z.B. HTTP-Plugin).
Das folgenden Code-Snippet erstellt ein Step zum Testen eines Pub/Sub-Mechanismus mit einem MQTT-Broker.
var step = Step.Create("step", async context => { var message = GetTestMessage(); try { await _mqttBroker.SendMessageAndWaitForResponseAsync( message, TimeSpan.FromSeconds(1)); return Response.Ok(); } catch (Exception ex) { return Response.Fail(ex.Message); } });
Das Framework erwartet als Rückgabe eines Steps ein passendes Ergebnis – Ok() oder Fail().
Testszenarios werden aus einem oder mehreren Steps zusammengefügt. Sie definieren die Art und die Zeitdauer des Lasttests. Entscheidend für einen aussagekräftigen Test ist die Konfiguration der passenden Art der simulierten Last (Load Simulation). Aktuell sind fünf Load Simulations verfügbar, welche für offene oder für geschlossene Systeme geeignet sind.
Offene System können von den Clients beliebig aufgerufen werden. Die Antworten werden vor einem erneuten Aufruf nicht abgewartet. Dies sind beispielsweise Webseiten oder Web-APIs. Zu konfigurieren ist daher die Anzahl Aufrufe pro Sekunde.
Simulationsarten:
Bei geschlossenen Systemen ist die Anzahl von Clients beschränkt. Vor einem erneuten Aufruf wartet ein Client die Antwort ab. Ein typisches Beispiel für ein geschlossenes System ist eine Datenbank mit Zugriffen über einen Connection-Pool. Zu konfigurieren ist daher die Anzahl an Clients.
Simulationsarten:
Der folgende Code-Block zeigt ein Testszenario für ein offenes System, welches eine konstante Last von 200 Anfragen pro Sekunde für die Dauer von 2 Minuten erzeugt.
var rate = 200; var scenario = ScenarioBuilder .CreateScenario($"Pub/Sub test with {rate}", step) .WithLoadSimulations( Simulation.InjectPerSec(rate, TimeSpan.FromSeconds(120)));
Der Runner führt die konfigurierten Szenarios aus. Als Optionen werden Logging und Reporting konfiguriert. Je nach Anwendungsfall kann der Runner im Rahmen eines UnitTests oder mit einer Konsolenapplikation ausgeführt werden. Hilfreich für das UnitTesting sind die von der Run-Methode zurückgegeben statistischen Daten, da mit ihnen passende Asserts geschrieben werden können. Spannend ist auch die Möglichkeit die Tests in einen Container zu deployen. Damit können die Tests direkt in der Cloud oder auf dem Zielrechner (z. B. Edge-Device) ausgeführt werden.
NBomberRunner .RegisterScenarios(scenario) .WithTestName($"Test with {rate} requests per second") .Run();
Der Runner führt die konfigurierten Szenarien simultan aus und zeichnet die gewünschten Metriken auf. Die Ausführung der Testschritte (Steps) in einem Szenario erfolgt dagegen sequentiell. Damit können mehrere logische Flows (z. B. Login => Aktion 1 => Aktion 2 => Logout) erstellt werden, welche dann parallel ausgeführt werden. Dank diesem Design sowie der Fluent-API lassen sich auch komplexe Testszenarien einfach und effizient erstellen.
Standardmässig wird ein einfacher Report direkt in die Konsole ausgegeben. Zusätzlich werden in einem Ordner im bin-Verzeichnis die Reports in den Formaten HTML, Markdown, CSV und Text ausgegeben. Weitere Konfigurationen zu den Reports können beim Auruf des Runners über die Fluent-API mitgegeben werden.
Konsolenoutput von NBomber mit einfacher Tabelle der Lasttest-Messwerte: Anzahl Aufrufe, gemessene Antwortzeiten sowie einfache statistischen Metriken (Mittel, Varianz, Perzentile):
Beispiel eines HTML-Reports zu einem Ramp-Up Test, welcher zeigt, wie das getestete System ab einer gewissen Last beginnt Fehler zu produzieren.
Das erstellen von Lasttests mit NBomber geht leicht und effizient. Mit den vorhandenen Testbausteinen lassen sich auch komplexe Testszenarien relativ einfach erstellen. Nützlich sind der direkte Output der Resultate in die Konsole sowie die weiteren Reports im Fileformat.
Wer Lasten für sehr grosse Systeme simulieren will und Dinge wie Real-Time-Reporting braucht, findet diese zudem in den kostenpflichtigen Erweiterungen von NBomber Enterprise.
Schreiben Sie einen Kommentar