Wie man mit Cypress.io und Selenium automatisierte Tests für Feature-Flags schreibt

Todd SellerTodd Seller
26. März 2020

Bei Optimizely setzen wir größtenteils auf Feature-Flags, da wir dadurch unsere Release-Zyklen verkürzen, A/B-Tests durchführen und Codeänderungen sicherer per Rollout bereitstellen können. Feature-Flags (auch Feature-Toggles genannt) haben uns zwar geholfen, bessere Produkte schneller auf den Markt zu bringen, sind aber oft sehr komplex.

Bei Optimizely setzen wir einen Großteil unseres Codes auf Feature-Flags, da wir dadurch unsere Release-Zyklen verkürzen, A/B-Tests durchführen und Codeänderungen sicherer mit Rollouts bereitstellen können. Feature-Flags (auch Feature-Toggles genannt) haben uns zwar geholfen, bessere Produkte schneller auf den Markt zu bringen, aber die Erstellung von automatisierten Tests gestaltet sich oft sehr schwierig. Feature-Flags führen naturgemäß zu nicht-deterministischem Code, was beim Schreiben von automatisierten Tests erhebliche Probleme verursacht. Eine Analogie, die ich gerne verwende, ist folgende: Automatisierte Tests sind wie Züge, der Code wie Gleise. Automatisierte Tests eignen sich hervorragend, um zu überprüfen, ob die Gleise korrekt gebaut sind, da der Zug schnell die Strecke entlangfahren und bestätigen kann, ob alles richtig liegt. Beim Testen mit einem Feature-Flag können sich die Gleise jedoch je nach Logik des Flags ändern, und der Zug kann entgleisen, weil ein Teil der Strecke, auf der er fahren soll, nicht mehr verfügbar ist. Dies führt dazu, dass Ihre automatisierten Tests unzuverlässig werden und viele Fehlalarme auslösen. Aufgrund dieses Spannungsverhältnisses zwischen Feature-Flags und automatisierten Tests werde ich häufig von Entwicklern und Kunden gefragt: „Wie erstellt man automatisierte Tests für Feature-Flags?“ Hier bei Optimizely nutzen unsere Entwicklungsteams verschiedene Strategien, um unser Automatisierungs-Framework dabei zu unterstützen, deterministischen Code zu testen. Einige davon möchten wir Ihnen heute vorstellen.

Publikumsbedingungen

Mit Optimizely Full Stack können Sie eine spezifische Zielgruppenbedingung erstellen, die Ihr Test-Runner übergibt. Dadurch wird sichergestellt, dass der Test-Runner entweder immer oder nie in diesem Feature ausgeführt wird. Ein kurzer Hinweis zum folgenden Beispiel: Das Automatisierungsteam von Optimizely verwendet Cypress.io und Selenium für unsere End-to-End- und Regressionsautomatisierungstests. Dieses Beispiel wurde in Cypress.io geschrieben. Wir sind von Cypress.io begeistert, weil es schnell und einfach zu entwickeln ist, Screenshots und Aufzeichnungen ermöglicht und umfassende Berichtsfunktionen bietet. Unsere einfache Beispiel-App und den Code für unsere Cypress.io-Automatisierungstests finden Sie hier. In unserer Beispiel-App haben wir ein Optimizely-Feature-Flag um das Astronautenbild hinzugefügt. Wenn das Flag aktiviert ist, wird der Astronaut angezeigt (Feature aktiviert), andernfalls nicht (Feature deaktiviert).
Wir möchten, dass Cypress.io beide Zustände (Flag aktiviert/Flag deaktiviert) prüft und validiert, ob das Bild korrekt angezeigt oder entfernt wird. In Ihrem „Optimizely“-Feature-Flag erstellen wir eine Zielgruppenbedingung namens „cypress“. Wir möchten diese Bedingung auslösen, indem wir eine Übereinstimmung für jede Zeichenkette festlegen, die „on“ entspricht.
Im Cypress.io-Test-Runner übergeben wir den Abfrageparameter `cypress=on` und prüfen, ob die neue Funktion aktiviert ist. Dadurch weiß unser Cypress.io-Test-Runner genau, was er testen und überprüfen soll. Wie Sie unten sehen, führt der Cypress.io-Test-Runner unsere eigentlichen Testfälle in unserer App aus, schaltet zwischen aktivierten und deaktivierten Funktionen um und prüft, ob das Bild angezeigt wird bzw. nicht angezeigt wird.

Whitelist-Funktionalität

Optimizely bietet Ihnen außerdem die Möglichkeit, Ihren Test-Runner für einen Feature-Test auf eine Whitelist zu setzen (ein Feature-Test ist ein Experiment, das Sie mit einem bestimmten Feature-Flag durchführen können). Geben Sie eine Benutzer-ID an, die Ihr Test-Runner verwendet, um sicherzustellen, dass Cypress.io immer die Variante verwendet, die Sie testen möchten. Hinweis: Diese Funktion ist nur für Feature-Tests und nicht für Rollouts verfügbar. Im folgenden Screenshot sehen Sie, wie dies in Optimizely funktioniert.

Set erzwungene Variation

Optimizely nutzt außerdem Selenium-Tests, die auf einem BDD-Framework ausgeführt werden. Für diese Tests verwenden wir die Möglichkeit, direkt im SDK eine erzwungene Variation festzulegen. Das folgende Beispiel zeigt eine Selenium-Implementierung, die eine bestimmte Variante erzwingt und anschließend den Feature-Pfad validiert (Hinweis: Die erzwungene Variante funktioniert nur bei Feature-Tests, nicht bei Feature-Rollouts.).

Unten sehen Sie ein Gherkin-Beispiel, in dem der Selenium-Test-Runner sicherstellen soll, dass die getestete Variante immer die create_flow-Variante ist (die zu testende Variante) und nicht zufällig einer anderen Variante zugewiesen wird.

Szenario: Erstellen einer A/B-Kampagne mit URL-Targeting über die vereinfachte Erstellung flow     Gegeben Ich öffne einen Browser als Persona "V2User"     Dann erzwinge ich, dass der Bucket-Benutzer $acc_id in den "create_flow" des Experiments "exp1" gelangt. Wenn ich die Seite /v2/projects besuche, Dann sollte ich "Experimente" sehen. Unser eigentlicher Python-Code ruft das SDK auf und übergibt den Schlüssel des Experiments, die ID des Test-Runners und die zu testende Variante. Dies sind nur einige der Strategien, mit denen unser Automatisierungsteam bei Optimizely Feature-Tests und Feature-Rollouts durchführt, um sicherzustellen, dass neuer Code deterministisch getestet wird. Haben Sie eine tolle Strategie, die hier nicht aufgeführt ist? Oder haben Sie Fragen zu unserer Vorgehensweise? Wir freuen uns, von Ihnen zu hören! Kontaktieren Sie uns unter quality@optimizely.com

Wenn Sie mit Feature-Flag-Management und kontrollierten Rollouts beginnen möchten, sehen Sie sich unser kostenloses Flagging-Produkt an: Optimizely Rollouts.