Veröffentlicht am 26. März 2020

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

Bei Optimizely stellen wir einen großen Teil unseres Codes hinter Feature Flags bereit, weil wir dadurch unseren Release-Zyklus verkürzen, A/B-Tests durchführen und Codeänderungen bei Rollouts sicherer bereitstellen können. Feature Flags (auch bekannt als Feature Toggles) haben uns zwar dabei geholfen, bessere Produkte schneller zu liefern, aber sie sind auch sehr schwierig

Todd Seller
von Todd Seller
decorative yellow lines on background

Bei Optimizely stellen wir einen großen Teil unseres Codes hinter Feature Flags bereit, weil wir dadurch unseren Release-Zyklus verkürzen, A/B-Tests durchführen und Codeänderungen bei Rollouts sicherer bereitstellen können. Feature Flags (auch bekannt als Feature Toggles) haben uns zwar dabei geholfen, bessere Produkte schneller auszuliefern, aber es ist sehr schwierig, Automatisierungstests für sie zu schreiben. Es liegt in der Natur der Sache, dass Feature Flags dazu führen, dass Ihre Codebasis nicht deterministisch ist, was beim Schreiben von Automatisierungs-Tests für sie ein großes Chaos verursacht.

Eine Analogie, die ich gerne verwende, ist, dass man Automatisierungstests als Züge und den Code als Gleise betrachten könnte. Automatisierungstests sind erstaunlich gut geeignet, um zu überprüfen, ob die Gleise richtig gebaut sind, denn der Zug kann schnell über die Gleise fahren und Sie darüber informieren, ob alles an der richtigen Stelle ist. Wenn Sie jedoch gegen ein Feature Flag testen, kann es sein, dass sich Ihre Gleise aufgrund der Logik Ihres Flags ändern und Ihr Zug entgleist, weil ein Teil des Gleises, auf dem er eigentlich fahren sollte, nicht mehr verfügbar ist. Dies führt dazu, dass Ihre Automatisierungstests unzuverlässig werden und Ihnen viele falsch-positive Signale liefern.

Aufgrund dieses Spannungsverhältnisses zwischen Gleis und Zug oder Feature Flag und Automatisierungstest wird mir von verschiedenen Entwicklern und Kunden häufig die Frage gestellt: "Wie erstellen Sie Automatisierungstests gegen Feature Flags?"

Hier bei Optimizely verwenden unsere Entwicklungsteams eine Vielzahl unterschiedlicher Strategien, um unser Automatisierungsframework dabei zu unterstützen, sicherzustellen, dass der Code, den es testet, deterministisch ist. Einige davon möchten wir heute mit Ihnen teilen.

Publikumsbedingungen

Optimizely Full Stack ermöglicht es Ihnen, eine spezifische Audience-Bedingung zu erstellen, die Ihr Testläufer durchläuft und die sicherstellt, dass der Testläufer entweder immer in das Feature oder nie in das Feature eingeklemmt wird.

Eine kurze Anmerkung zum Beispiel unten. Bei Optimizely verwendet das Automatisierungsteam Cypress.io und Selenium, um unsere automatisierten End-to-End-Tests und Regressionstests durchzuführen. Dieses spezielle Beispiel wurde in Cypress.io geschrieben. Wir mögen Cypress.io sehr, weil es schnell und einfach zu entwickeln ist, Screenshots und Aufzeichnungen bietet und eine zuverlässige Berichterstattung ermöglicht. Sie finden unsere einfache Beispiel-App und den Code für unsere Cypress.io-Automatisierungstests hier.

In unserer Beispiel-App unten haben wir ein Optimizely Feature Flag um das Astronautenbild herum eingefügt. Wenn die Flagge eingeschaltet ist, sehen wir den Astronauten (Feature On), und wenn die Flagge ausgeschaltet ist, sehen wir ihn nicht (Feature Off).

feature on

feature off

Wir möchten, dass Cypress.io beide Bedingungen prüft (Flag On/Flag OFF) und feststellt, ob das Bild korrekt angezeigt oder entfernt wird.

In Ihrem Optimizely Feature Flag erstellen wir eine Audience Condition namens Cypress. Wir wollen diese Bedingung auslösen, also setzen wir eine Übereinstimmung für jede Zeichenkette, die gleich "on" ist.

audience condition

Im Cypress.io Test Runner übergeben wir den Abfrageparameter cypress=on und überprüfen, ob das neue Feature aktiviert ist.

it('Validieren Sie, dass die Funktion astro_boy aktiviert ist', function () { // Besuchen Sie die App mit dem Abfrageparameter audience cy.visit('/?cypress=on') // Validieren Sie, dass die Funktion aktiviert ist cy.get('#astronaut') .should('exist') })

Auf diese Weise weiß unser Cypress.io Test Runner genau, worauf er testen muss, und kann dies bestätigen.

Wie Sie unten sehen können, führt der Cypress.io Test Runner unsere eigentlichen Testfälle in unserer App aus, schaltet zwischen ein- und ausgeschalteten Funktionen um und stellt fest, ob das Bild angezeigt oder nicht angezeigt wird.

cypress.io test runner

Whitelist-Funktionalität

Optimizely bietet Ihnen auch die Möglichkeit, Ihren Test Runner für einen Feature-Test auf die 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 ein, die Ihr Test Runner verwenden wird, um sicherzustellen, dass Cypress.io immer die Variante sieht, gegen die Sie testen möchten. Hinweis: Diese Funktion ist nur für Feature-Tests und nicht für Rollouts verfügbar. Wie Sie dies in Optimizely tun, sehen Sie auf dem folgenden Screenshot.

feature rollout whitelist

Erzwungene Variation einstellen

Optimizely verwendet auch Selenium-Tests, die auf einem BDD-Framework ausgeführt werden. Für diese Tests nutzen wir die Möglichkeit, eine erzwungene Variation direkt im SDK festzulegen. Das folgende Beispiel ist eine Selenium-Implementierung, die eine Variation erzwingt und dann diesen Feature-Pfad validiert(Hinweis: Erzwungene Variationen funktionieren nur mit Feature-Tests und nicht mit Feature-Rollouts).

Unten sehen Sie ein Gherkin-Beispiel, bei dem unser Selenium Test Runner sicherstellen soll, dass die Variation, die wir testen, immer die create_flow-Variation ist (die Variation, die wir testen möchten) und nicht zufällig einer anderen Variation zugewiesen wird.

Szenario: Ich öffne einen Browser als Persona "V2User". Dann zwinge ich den Bucket User "$acc_id" in den "create_flow" des Experiments "exp1".Wenn ich "/v2/projects" besuche , sollte ich "Experimente" sehen .

Unser aktueller Python-Code ruft das SDK auf, übergibt den Schlüssel des Experiments, die ID des Testläufers und die Variante, die wir testen wollen.

assert fullstack.set_forced_variation( experiment_key, user_id, variation, datafile_key ), 'Set_forced_variation konnte nicht gelöscht werden' # Doppelprüfung assert fullstack.get_variation(experiment_key, user_id, datafile_key) is None, 'Set_forced_variation konnte nicht gelöscht werden'

Dies sind nur einige Strategien, mit denen unser Automatisierungsteam bei Optimizely unsere Feature-Tests und Feature-Rollouts angeht, um sicherzustellen, dass wir neuen Code deterministisch testen.

Haben Sie eine geniale Strategie, die hier nicht aufgeführt ist? Oder haben Sie Fragen zu dem, was wir tun? Wir würden uns freuen, mehr von Ihnen zu hören! Kontaktieren Sie uns unter quality@optimizely.com

Wenn Sie sich für die Verwaltung von Feature Flags und kontrollierte Rollouts interessieren, sollten Sie sich unser kostenloses Flagging-Produkt ansehen: Optimizely Rollouts.