Wie ich zu einer kleinen Qa-Automatisierung werden musste: Was ich fühlte, überlebte und die wunderbare Architektur und Infrastruktur des automatischen Testens mit den Augen eines vorbeikommenden Entwicklers.
Einführung
Wie sie sagen, ich bin kein Gynäkologe, ich ging einfach vorbei und beschloss zu schauen. Daher werde ich zunächst auf die Gründe für das Schreiben eingehen. Es scheint mir, dass ein Spezialist das Problem um eine Größenordnung schneller bewältigen und nicht so viele Rechen auf seinem Weg sammeln würde. Aber er wäre nicht so interessiert wie ich, und Sie hätten nichts zu lesen.
Ein weiterer Grund, der mich zum Schreiben veranlasste: Ich verstand eine ganze Weile nicht, was an der Infrastruktur von Autotests so besonders war. Darüber hinaus haben viele Manager von PM und höher auch nicht vollständig verstanden, was dort so kosmisch ist und warum Entwickler Unit-Tests für ein oder zwei selbst schreiben, und für die Phycestests werden einzelne Leute genommen, die Tests langsamer schreiben, ständig etwas reparieren und Die Chance, alle Finanzspezifikationen zu bestehen, liegt streng unter 100%, vorausgesetzt, die Stichprobe ist groß genug.
Das Problem
Am dritten Tag fiel die Issue-Spezifikation für das Eisenbahnprojekt. Irgendwann eine Woche zuvor hat unser einziger Automatisierungstechniker beschlossen, in Chicago zu arbeiten, und wir haben noch keinen neuen Spezialisten gefunden. Deshalb musste ich meine Ärmel hochkrempeln und so tun, als wäre ich QS. Über wie es war und versuchen zu erzählen.
Das Problem sieht ziemlich harmlos aus. Aber für den Anfang ein wenig Hintergrund und Beschreibung der Umgebung. Wir haben viele Adresswähler in unserer Plattform. Ehrlich gesagt ist dies eine der Hauptentitäten der Plattform. Selektoren gehen zu Google API für Daten. Bei Autotests werden alle Anforderungen blockiert, um Geld zu sparen und Tests zu beschleunigen. Außerdem wurde ein wenig Logik hinzugefügt, um ungefähr dieselbe Adresszeile zu erhalten, die angefordert wurde, ohne zu externen Diensten zu gehen.
Was ist kaputt gegangen: Wir geben die gewünschte Adresse in die Adressleiste ein, ein Dropdown-Feld mit mehreren Optionen wird angezeigt, wir wählen die gewünschte aus und ... der Wert des benachbarten Elements wird in die Eingabe eingefügt. Immer.
Ein langer Weg zur Wahrheit
Erste Hypothesen und naiver Ansatz
Ohne weiteres machte ich den nächsten Falltest, fand die Zeile, in der die Adresse ausgewählt wurde, und begann, sie und die Nachbarn sorgfältig zu untersuchen. Die Zeile sieht harmlos aus: new_order_page.destination_address.select(baker_street)
. Aber wir verstehen, dass hinter einem schönen Code immer ein paar seltsame kleine Designs und unangenehme Eingeweide stecken.
Ich erinnerte mich schnell daran, dass all diese Wirtschaft auf SitePrism funktioniert . Diese Sache ermöglicht es, die Seite und die darauf befindlichen Elemente in die Klassen- bzw. Klassenmethoden einzuschließen. Für Klicks und andere Aktionen sind Capybara und RSpec verantwortlich. Aber sie haben keinen Zweifel, sie sind zuverlässig wie die gesamte zivile Flotte. Und wenn ja, bietet sich sofort die erste Hypothese an: Entweder hat jemand schlecht Selektoren für das Prisma geschrieben, oder jemand hat das Layout vorne verdreht.
Der erste Teil der Hypothese verschwand schnell, Selektoren sind perfekt geschrieben. Dort wurde kein xpath
mit der Wahl des dritten li
innerhalb des Elements gefunden und der Code selbst hat sich im letzten Jahr nicht geändert.
Im Bereich der Auswahlmethode wurde jedoch die Logik mit regulären Ausdrücken angehäuft, um die gewünschte Option aus der Dropdown-Liste auszuwählen. Natürlich ärgere ich mich über Regexps und gehe, um sie zu überprüfen. Ich verbringe eine halbe Stunde und verstehe, dass alles gut funktioniert. Es wird genau die Zeile ausgewählt, die benötigt wird. click
wird darauf aufgerufen. Und alles sollte funktionieren. Das heißt, der zweite Teil der Layouthypothese verschwindet ebenfalls. Aber der Gedanke erscheint über die js
Kurve. Immerhin ist das Element auf der Seite, das wir haben, benutzerdefiniert, js
in der js
Reihenfolge um es herum und darüber hinaus js
in diesem js
gerade erst daran js
.
Js ist schuld
Dies ist der Standardgrund für alle undurchsichtigen Probleme. So etwas wie "Geh zu js
, weil er schon geschockt ist." Und es scheint, in meinem Fall könnte auch nicht ohne js
. Im Allgemeinen renne ich ohne nachzudenken zum Front-End-Team und zeige mit dem Finger auf die fallenden Tests. "Alles funktioniert auf unserer Seite, bitte reparieren Sie Ihre Seite."
Aber die Jungs vom Dandy sind kein Miss, sie suchen ein paar Stunden dort herum, finden ein paar Fehler, die nicht mit der Erzählung zusammenhängen, und sagen, dass js
nicht schuld ist! Gleichzeitig werfen sie interessante Informationen auf, dass eine Anfrage für die Auswahl nicht ausreicht, und er macht eine andere, deren Antwort genau mit dem falschen Inhalt der Eingabe übereinstimmt.
Ich habe eine solche Wende nicht erwartet. Wir müssen zurückgehen und herausfinden, wie der Schein von Anfragen für uns funktioniert.
Umfassender Ansatz
Es gibt also keinen anderen Ort, an dem man auf Hilfe warten kann. Moskau ist hinter uns und solche Sachen.
Zunächst untersuchen wir die Möglichkeiten von Moka-Anfragen an Google. Genauer gesagt suchen wir zuerst, wo dies geschieht. Dies ist keine triviale Aufgabe. Es stellt sich heraus, dass wir ein ganzes Modul MockServices::Base
, das für die MockServices::Base
verschiedener Anforderungen mit dem Videorecorder verantwortlich ist . Er kniet schlau im Basis-Controller und kann nur wegen des Namens des Dienstes, der für externe Anfragen verantwortlich ist, nicht gefunden werden.
Okay, habe den Moki gefunden. Nun schauen wir uns ihre Implementierung an. Die erste Anfrage wird einfach nass: Informationen von params
werden genommen und durch die Antwort in die Vorlage ersetzt. Nur für den Fall, ich habe den Inhalt der params
überprüft und wie erwartet kommt alles so, wie es sollte.
Interessanter ist die Moka-Methode der nächsten Anfrage. mock_data
erscheint eine Art mock_data
. Dies sind keine params
und wir müssen herausfinden, woher dieses Datum kommt. Nach fünfmaligem Eintauchen wird festgestellt, dass diese Daten mit dem Schlüssel x_mock_data
aus dem RequestStore x_mock_data
. Schon interessanter.
Wir kehren zum ursprünglichen Test zurück und stellen fest, dass es eine set_mock_header
Sache gibt, die bei näherer Betrachtung einige Daten zum gleichen RequestStore
. Interessanter!
Irgendwann in diesem Moment tritt eine kognitive Dissonanz im Kopf auf: Einerseits ist es die wahrscheinliche Ursache des Problems, die globalen Variablen, die uns die Nebenanforderung gibt, sind kaputt. Es gibt jedoch eine Nuance: Der Server für die Finanzspezifikationen und die Finanzspezifikationen selbst sind zwei unabhängige Prozesse (tatsächlich besteht der Server aus mindestens drei Prozessen). Daher kann eine Belastung mit Guthaben in keiner Weise konvergieren, da noch keine globalen Variablen zwischen den Prozessen in diese Welt gebracht wurden. Und mit einem Multithread-Webserver wird es ein heftiges Spiel, das physisch nicht funktioniert. Bedeutet, ich habe etwas ausgehöhlt und es ist notwendig zu suchen.
Wir schauen weiter und finden einen bestimmten bm
, auf den die Überschriften setzen. Machen Sie weiter und stellen Sie fest, dass bm
BrowserMob ist . Dann habe ich ein bisschen rumgespielt, denn es ist ein Proxy auf Java in einem Ruby-Wrapper. Nur ein Klavier im Gebüsch.
Wir beginnen mit der weiteren Auswahl und verstehen, dass für die "globalen" Variablen zwischen dem Client mit rspec
und dem Server mit der Anwendung (z. B. puma ) dieselben X-Mock-Data
Header in der Anforderung verwendet werden. Das Problem ist, dass die Anwendung nichts über diese Leser wissen sollte. Zu diesem Zweck benötigen Sie einen Proxy, über den alle Anforderungen übertragen werden und der die Einrichtung der Header übernimmt. Listig wirst du nichts sagen.
Wir gehen zum Testen und stellen fest, dass genau dieses Ding nicht funktioniert. Überschriften sind nirgends zu sehen: weder in Anfragen noch in Antworten. Der RequestStore ist jedoch auf der rspec
Seite gefüllt und auf der Webserverseite leer. Das heißt sicher - es ist im Proxy.
Dazwischen stellt sich heraus, dass wir nicht nur Tests mit set_mock_header
Adressen set_mock_header
, sondern auch alles, was den obigen set_mock_header
.
Großartig. Es bleibt zu verstehen, wie dies behoben werden kann.
Wir haben es mit einem Proxy zu tun
Wir lassen die Grabungspunkte in der Region weg, in der die jar
Datei gestartet wird, und steuern sie dann über Ruby. Achten Sie besser auf die Art und Weise, wie der Browser-Proxy angegeben wird. Wir verwenden Chrome und übergeben Proxy-Informationen in einem der vielen Argumente der Befehlszeile, wenn diese gestartet wird. Die Proxy-Funktion besteht darin, dass wir die pac
Datei verwenden, die wir aus der Vorlage generieren, um den Datenverkehr von Web-Sockets über den Proxy zu verhindern.
Irgendwo hier besteht der Wunsch, mit der Proxy-Konfiguration zu googeln, was auf dem Chrome steht. Es stellt sich heraus, dass Sie nicht weit gehen müssen und in Version 72+ haben die Jungs seine Arbeit "beendet". Bei dieser Gelegenheit brachten sie sogar einen separaten Fehler . Mein Lieblingskommentar:
"Können Sie bitte aufhören, Funktionen zu ENTFERNEN?"
Die Traurigkeit ist, dass es als ein Merkmal angesehen wird und sie in Zukunft noch mehr Zinn in Bezug auf "Geheimhaltung" versprechen.
Kurz gesagt, Chrome unterstützt das file:
protocol im proxy-pac-url
Argument nicht mehr. Die Lösungen sind besser als die anderen:
js
das Argument js
, das die pac
Datei liest und in base64 --proxy-pac-url='data:application/x-javascript-config;base64,'$(base64 -w0 /path/to/pac/script)
: --proxy-pac-url='data:application/x-javascript-config;base64,'$(base64 -w0 /path/to/pac/script)
;- Erhöhen Sie Ihren Webserver in Python, um eine Datei gemäß einem "korrekteren" Protokoll zu verteilen, das im Argument für
pac
proxy unterstützt wird. - Schalten Sie
NetworkService
und dann sollte das file:
protocol funktionieren, aber sie versprechen, dass es auch in Zukunft "repariert" wird.
Die ersten beiden Optionen haben mich sicherlich nicht inspiriert, und die dritte hat seltsamerweise geholfen.
Kurzlebige Freude
Ich freute mich, dass eine schwierige Verbindung zwischen Leerlauf-Dropdowns und aktualisiertem Chrom gefunden wurde, und war nicht lange glücklich. Es stellt sich heraus, dass unser CI nicht nur Chrome, sondern auch alle angrenzenden Pakete aktualisiert hat, und jetzt Selenium::WebDriver::Error::NoSuchDriverError
noch mehr Tests aufgrund eines unbekannten Fehlers ab. Selenium::WebDriver::Error::NoSuchDriverError
, der seltsamerweise nicht mit chromedriver zusammenhängt , sondern verwandt ist mit einer Chrome-Konfiguration, Bibliotheksversionen und paralleler Ausführung von Spezifikationen.
Aber das ist die Aufgabe für den nächsten Arbeitstag ...
Mit Blick auf die disable-dev-shm-usage
: Das Argument disable-dev-shm-usage
hat dort geholfen.
Schlussfolgerungen
Schimpfe nicht mit der Automatisierung. Er scheint am meisten unter äußeren Umständen zu leiden, die von ihm unabhängig sind.
Es ist besser, mit den Entwicklern einen Freund des Automatisierungsingenieurs zu finden, damit diese ihre Infrastruktur organisieren mit Präferenz und Kurtisanen mit festen Versionen und einer kontrollierten Testumgebung. Für mich ist dies besser, als an einem proprietären CI zu leiden, von dem jedes seine eigenen hoch entwickelten Krücken und Unterwasserhocker hat, die Sie erst nach einer engen Integration Ihrer Anwendung und Tests mit der Umgebung eines anderen kennenlernen werden.