
Teilen Sie:
Max ist ein Python-Entwickler und Software-Ingenieur, der sich für Kommunikations-APIs, maschinelles Lernen, Entwicklererfahrung und Tanz interessiert! Er hat Physik studiert, aber jetzt arbeitet er an Open-Source-Projekten und stellt Dinge her, die das Leben von Entwicklern verbessern.
Verbessern Sie mit Mutationstests Ihre Fähigkeiten in der Softwareentwicklung!
Lesedauer: 22 Minuten
Die Codeabdeckung (der Prozentsatz des Codes, der bei der Ausführung Ihrer Tests ausgeführt wird) ist eine hervorragende Kennzahl. Die Codeabdeckung sagt jedoch nichts darüber aus, wie gut Ihre Tests Änderungen an Ihrer Codebasis erkennen, da es sich um eine quantitative Kennzahl handelt. Wenn Ihre Tests nicht gut konzipiert sind, können Änderungen zwar Ihre Unit-Tests bestehen, aber die Produktion stören.
Mutationstests sind eine großartige (und stark unterschätzte) Methode, um festzustellen, wie sehr Sie Ihren Tests vertrauen können. Mutationstests funktionieren, indem Sie Ihren Code auf subtile Weise verändern und dann Ihre Unit-Tests auf diese "veränderten" Versionen Ihres Codes anwenden. Wenn Ihre Tests fehlschlagen, großartig! Wenn sie bestehen, bedeutet das, dass Ihr Test nicht gut genug war, um diese Änderung zu erkennen.
In diesem Video zeigt Ihnen Max vom Vonage Developer Experience Team, wie Sie mit Mutationstests in jeder Sprache beginnen und wie Sie sie in Ihre CI/CD-Pipeline integrieren können. Schon bald wird das Auffinden von mutiertem Code ein Routinebestandteil Ihres Release-Engineering-Prozesses sein, und Sie werden Pinguine nie wieder auf dieselbe Weise betrachten!
Nachfolgend finden Sie die Abschrift des Videos sowie einige praktische Links.
Hier können Sie sich für ein kostenloses Entwickler-Konto bei Vonage anmelden.
Wenn Sie irgendwelche Fragen haben, wenden Sie sich bitte an uns auf unserem Community Slack.
Hallo. Mein Name ist Max und ich bin ein Entwickler-Befürworter bei Vonage. Und heute möchte ich mit Ihnen über Mutationstests sprechen. Ich möchte Ihnen sagen, wie ich es verwende und wie Sie es auch verwenden können. Bevor wir beginnen, möchte ich kurz das Unternehmen erwähnen, für das ich arbeite.
Wir sind ein Unternehmen namens Vonage und beschäftigen uns u. a. mit Kommunikations-APIs. Ein großer Teil des Codes, mit dem ich arbeite, sind also Dinge wie SMS versenden oder Voice-Anrufe tätigen, Video-Chats erstellenund ähnliche Dinge. Es gibt also eine Menge Dinge, die mit Kommunikation zu tun haben. Der Grund, warum ich das erwähne, ist, dass ich tatsächlich Mutationstests auf unseren Code angewendet habe. Ich möchte Ihnen zeigen, wie ich das gemacht habe, warum das eine gute Wahl für uns war, und ich möchte Ihnen zeigen, wie Sie das auch tun können. Aber bevor ich wirklich anfange, möchte ich Ihnen den eigentlichen Protagonisten dieses Vortrags vorstellen.
Ich bin der Sprecher, aber der eigentliche Protagonist ist eigentlich Henry. Das hier ist Henry. Sie können hoffentlich sehen, dass er ein süßer kleiner Pinguin ist. Und der Grund, warum er hier die wirklich wichtige Figur ist, liegt darin, dass ich, als ich lernte, Mutationstests selbst anzuwenden, Henry als Analogie für eine Menge Dinge benutzte. Sie werden sehen, warum, denn ich werde ihn heute auch benutzen, um Ihnen zu zeigen, wie Mutationstests wirklich funktionieren. Bevor wir beginnen, sollten wir ein paar Grundlagen schaffen.
Zuallererst möchte ich Sie bitten, über Folgendes nachzudenken: Haben Sie schon einmal von Tests gehört? Ich gehe davon aus, dass Sie, wenn Sie dieses Video angeklickt haben, wahrscheinlich wissen, was Testen für Software ist.
Ich möchte, dass Sie auch über Code Coverage nachdenken. Vielleicht kennen Sie Code Coverage, vielleicht auch nicht. Machen Sie sich keine Sorgen, wenn Sie sie nicht kennen, denn das ist etwas, das wir auf jeden Fall noch erwähnen werden. Es gibt auch Mutationstests. Ich nehme an, Sie haben schon davon gehört, wenn Sie den Titel dieses Videos gesehen haben, aber es ist eine wirklich nützliche Sache für sich. Und ich hoffe, dass Sie am Ende des Videos sehr viel mehr über Mutationstests wissen und sie selbst anwenden können. Wenn sich das für Sie also gut anhört, dann lassen Sie uns fortfahren!
Ich möchte nur eine Art Grundlinie festlegen. Deshalb möchte ich zuallererst das Testen erwähnen. Die große Frage ist also: Warum schreiben wir Unit-Tests? Welche Gründe haben wir, Tests für unseren Code zu schreiben? Und vielleicht möchten Sie das hier unterbrechen und selbst darüber nachdenken. Vielleicht aber auch nicht. Das ist auch in Ordnung.
In diesem Fall werde ich Ihnen zeigen, was ich mir darunter vorstelle. Und hier ist, was ich habe. Sie können sie also schreiben, um zu beweisen, dass Ihr Code funktioniert. Sie können sie aus Gründen der Dokumentation schreiben, um das Vertrauen in Ihren Code zu stärken, für Regressionstests, für Refactoring und auch aus Gründen der Compliance.
Im Grunde sind das alles Dinge, die Sie dazu ermutigen könnten, einen Unit-Test zu schreiben. Und es ist großartig, dass wir das haben, es ist großartig, dass wir eine Möglichkeit haben, zu überprüfen, ob unser Code funktioniert. Es ist großartig, dass wir eine Möglichkeit haben, zu dokumentieren und all diese großartigen Dinge. Aber es gibt hier auch ein kleines Problem. Das Problem ist, dass man vielleicht mit einem kleinen Projekt anfängt, aber dieses Projekt kann schnell wachsen, und was es tut, kann sich mit der Zeit entwickeln. Und wenn man dann Refactors und dergleichen durchführt, kann man Code vermissen, man kann Abschnitte auslassen. Sie könnten Dinge auslassen. Vielleicht testen Sie nicht mehr Ihren gesamten Code. Und das Problem dabei ist, dass wir unsere Tests oft nicht überwachen.
Wenn wir unsere Tests nicht überwachen, wissen wir nicht, was mit unserem Code nicht in Ordnung ist, weil wir keine Möglichkeit haben, ihn zu testen, und wir wissen nicht, ob die Tests uns helfen werden. Wir können also hoffentlich erkennen, worin hier die Herausforderung besteht. Ich würde gerne sagen, dass es besser wird, weil wir eine Codeabdeckung haben, richtig? Und wenn Sie nicht wissen, was das ist, erkläre ich es Ihnen kurz. In meinen Worten heißt das: "Wie viel vom Quellcode eines Programms wird ausgeführt, wenn die Testsuite läuft". Das ist die Art, wie ich es erklären würde.
Aber lassen Sie uns aufhören, darüber zu reden, und zeigen wir Ihnen ein echtes Beispiel aus der Praxis. Dies ist eines der Open-Source-SDKs, die ich betreue. Im Grunde handelt es sich um ein Python-SDK, das API-Aufrufe für verschiedene Dinge ermöglicht. Wir haben eine API, die ich in diesem SDK unterstütze, unsere Messages API. Damit kann man Nachrichten per SMS, MMS, WhatsApp, Facebook und so weiter verschicken - über viele verschiedene Kanäle. Ich habe mir den Code besorgt und einige Code-Coverage-Metriken darauf angewendet, um zu sehen, welche Anweisungen im Code ich getestet habe und welche Anweisungen mir fehlten. Sie können hier sehen, dass ich das meiste abgedeckt habe, aber es gibt eine fehlende Anweisung in Zeile 23 und diese Zeile sagt mir, oh, dafür habe ich keinen Test geschrieben.
In diesem Fall habe ich diese Art der Authentifizierung nicht ausprobiert. Das bedeutet also, dass ich einen Test dafür schreiben kann. Die Codeabdeckung hat also bereits meinen Code verbessert, und das ist großartig! Was kann es sonst noch tun?
Sie können sich damit einen Überblick über Ihr gesamtes Projekt und die verschiedenen Aussagen darin verschaffen - im Grunde genommen darüber, wie groß Ihr Deckungsgrad ist. Und so sieht das für mich aus. Und das scheint großartig zu sein. Es gibt hier wirklich ein großes Potenzial, denn erstens können Sie damit mehr und bessere Tests schreiben.
Es ist auch sehr einfach und billig, diese Dinge zu messen. Es ist nicht sehr rechenintensiv, die Codeabdeckung durchzuführen und zu sagen, "was habe ich abgedeckt"? Die andere gute Sache, die wirklich beste Sache hier ist, dass es zeigt, was Sie nicht getestet haben und so wissen Sie, hey, ich muss darauf achten, dass. Wenn ich diesem Code nicht traue, was man wirklich oft nicht tun sollte. Das ist wirklich nützlich. Die Codeabdeckung deckt also wirklich eine Menge ab.
Ich glaube, wir sind hier fertig, vielen Dank. Es war schön, heute mit Ihnen zu sprechen. Wir sehen uns wieder... außer, dass es tatsächlich einige Dinge gibt, die nicht so gut sind.
Nun, zunächst einmal kann die Codeabdeckung ein wenig irreführend sein. Sie garantiert auch nicht die Qualität Ihrer Tests. Ich werde Ihnen also ein Beispiel für ein sehr einfaches Stück Python-Code zeigen, hier ist es. Alles, was ich hier tue, ist das Importieren des requests Modul, das ist die Bibliothek, die ich benutze.
Dann mache ich einen API-Aufruf mit dieser Bibliothek. Alles, was ich tue, ist also eine GET-Anfrage an eine bestimmte URL, und dann bekomme ich die Antwort zurück und gebe das JSON der Antwort an den Benutzer zurück. Und das ist gut so. Das ist alles gut. Auf der nächsten Folie, der nächsten Seite, sehen wir, was ich hier habe, nämlich einen Test dafür.
Es hat zwar eine 100%ige Abdeckung, ist aber nicht sehr nützlich. Wir können hier sehen, dass wir etwas haben, das die API aufruft. Aber eigentlich ruft es die API auf und sagt dann nur, wenn ich sie aufgerufen habe, ist das gut. Wenn der Code ausgeführt wurde, ist alles in Ordnung. Was aber nicht funktioniert, ist die Validierung aller Dinge, die zurückkommen könnten.
Es kann sein, dass wir eine Antwort erhalten, die 200 Punkte beträgt. Vielleicht bekommen wir eine 400. Vielleicht bekommen wir etwas anderes. Vielleicht bekommen wir etwas, das wir nicht erwarten, und wir behandeln keinen dieser Fälle. Und wir testen auch nicht auf einen dieser Fälle. Dieser Test ist also nicht sehr nützlich, um Ihnen dabei zu helfen.
Ich möchte also ganz kurz eine Frage stellen: Haben Sie jemals ein Stück Code geschrieben und dann einen Test dafür geschrieben, nicht weil dieser Test nützlich sein sollte, sondern weil Sie Ihre Codeabdeckung ein wenig erhöhen wollten? Ich habe das getan und viele andere auch. Wenn Sie es nicht getan haben, toll, ich bin stolz auf Sie, aber in Wirklichkeit haben die meisten von uns diese Art von Dingen getan.
Was bei der Codeabdeckung oft passiert, ist, dass wir sie zu einem Ziel machen und nicht zu etwas, das uns Einblicke geben soll. Und das ist ein Prinzip, das einen Namen hat. Es gibt ihn wirklich, und er heißt Goodharts Gesetz. Es gilt nicht nur für die Testabdeckung, aber die Aussage lautet im Wesentlichen so: "Wenn eine Metrik zu einem Ziel wird, hört sie auf, eine gute Metrik zu sein".
Das ist wirklich wichtig, deshalb sage ich es noch einmal: "Wenn eine Kennzahl zu einem Ziel wird, hört sie auf, eine gute Kennzahl zu sein". Was will ich damit sagen? Nun, ich meine damit, dass wir die Codeabdeckung genommen haben, die uns eigentlich etwas über unseren Code und unsere Tests und deren Funktionsweise sagen soll, aber wir haben sie in eine Zahl verwandelt, die wir optimieren wollen.
Anstatt also über bessere Tests nachzudenken, denken wir über die Optimierung einer Zahl nach, die nicht so gut ist. Das wirft einige Fragen auf. Wie können wir zum Beispiel verstehen, was unsere Tests wirklich tun? Woher wissen wir, ob unsere Tests vertrauenswürdig sind? Die beste Aussage hierzu stammt von dem römischen Denker Juvenal (nach dem vierten Glas Wein), der um das Jahr 100 n. Chr. die Frage stellte: "Wer wacht über die Wächter?". Wer kümmert sich um die Leute, die sich um uns kümmern sollten. Und wer prüft unsere Tests?
Ich behaupte, dass ich heute eine Antwort für Sie habe, und ich behaupte, dass die Antwort Mutationstests sind. Sie haben vielleicht bemerkt, dass Henry wieder aufgetaucht ist.
Und das ist großartig, denn erstens ist er liebenswert, aber noch wichtiger ist, dass er uns jetzt helfen wird. Als ich letztes Jahr anfing, etwas über Mutationstests zu lernen, habe ich viel darüber nachgedacht, wie ich sie auf meinen Code anwenden könnte, und ich habe mir überlegt, wie ich das für mich selbst konzeptualisieren und verstehen könnte. Dabei habe ich mir vorgestellt, dass mein Code, der im Grunde viele API-Aufrufe sendet und mit API-Aufrufen und Nachrichten zu tun hat, wie eine Taube oder ein Täubchen ist, wie ein Vogel, der fliegen kann. In dieser Analogie kann ich also eine Nachricht an das Bein des Vogels binden und den Vogel loslassen, so dass er wegfliegt und meine Nachricht übermittelt.
Er wird also wegfliegen und tun, was ich von ihm verlange. Die Sache mit den Pinguinen ist, dass sie Vögel sind, also erfüllen sie diese Kriterien, aber sie können nicht fliegen, wie Sie vielleicht wissen, sie können nicht fliegen, und das macht sie irgendwie wütend. Aber noch wichtiger ist, dass eine Mutation auf diese Weise wie ein normaler Vogel ist, der in einen Pinguin verwandelt wurde, der nun nicht mehr das tun kann, was ich brauche, nämlich dass er fliegt. Schauen wir uns ein echtes Beispiel mit Bildern von Vögeln an, denn das ist es, was wir heute tun.
Zunächst beginnen wir mit einem Produktionscode, der wie erwartet funktioniert. Dann führen wir eine Art Mutationsoperation durch und erstellen eine mutierte Version dieses Codes. Wir haben also zum Beispiel diese Funktion, das ist Python. Sie addiert einfach 2 Numbers und gibt die Summe dieser 2 Numbers zurück. Eine mutierte Version dieser Funktion könnte zum Beispiel Zahlen subtrahieren oder eine Konstante hinzufügen oder die Addition der beiden Zeichenketten zurückgeben, usw.
Es könnte überhaupt nichts zurückgegeben werden, oder eine der logischen Operationen, die das Ergebnis dieser Codezeile verändern können. Was machen wir also mit Mutationstests? Wir haben einige Mutanten erstellt, was machen wir als nächstes?
Nun, ich nehme die Mutanten, die wir haben. Ich nenne sie aus offensichtlichen Gründen die Fab 4, und im Wesentlichen müssen wir sie gegen unsere Testsuite laufen lassen. Wir nehmen also jede Mutante. Und was wir in dieser Analogie im Wesentlichen tun, ist zu sehen, ob die Mutante fliegen kann, ob sie den Test besteht, den sie braucht, um wegzufliegen und die Nachricht zu überbringen. Henry, unser schöner Mutantenpinguin, muss also versuchen zu fliegen.
Wenn wir also diese Mutante nehmen, führen wir unsere Testsuiten durch. Und im besten Fall werden unsere Tests fehlschlagen. Das ist gut, denn es bedeutet, dass wir Henry als das entlarvt haben, was er ist, nämlich ein liebenswerter Pinguin, was großartig ist, weil es bedeutet, dass wir ihn nicht in die Produktion gehen lassen. Wir haben ihn in unseren Tests erwischt. Wenn die Tests nun erfolgreich sind, ist das ein schlechter Zeitpunkt, denn wir haben nicht bemerkt, dass Henry ein Pinguin und keine Taube ist.
Und er ist in der Lage zu fliegen. Ich meine, sieh dir diese Flügel an, dieser Pinguin kann einen Bus hochheben, oder? Sehr beeindruckend. Aber das bedeutet, dass dieser Mutant in die Produktion gelangen könnte, und das wollen wir nicht. Was bringt uns das also?
Und ich behaupte, dass uns dies eine Möglichkeit bietet, die Qualität unserer Tests zu bewerten. Das ist es, was Mutationstests ausmacht.
Lassen Sie uns über ein paar Frameworks sprechen, die Sie vielleicht in Erwägung ziehen sollten. Bei Frameworks gibt es verschiedene Optionen für verschiedene Sprachen, jede Sprache hat irgendeine Version davon. In meinem Fall verwende ich mutmut, ein auf Python basierendes Framework für Mutationstests.
Aber wenn Sie sich für andere Sprachen interessieren, gibt es Dinge wie Pitest für Java oder Stryker für JavaScript, C# und so weiter. Es gibt also Optionen für mehrere Sprachen. Und wenn die Sprache nicht erwähnt wurde, gibt es wahrscheinlich trotzdem etwas für sie. Ich bin kein professioneller Arzt, Finanzberater, Lehrer oder etwas in der Art - der Wert Ihrer Investition kann sowohl steigen als auch fallen. Aber am wichtigsten ist für mich, dass ich über das spreche, was ich benutzt habe.
Ich werde heute über Mutmut sprechen, weil ich es selbst verwendet habe. Und ich habe diese Mutationsprüfung auf mein eigenes SDK angewendet, und ich werde Ihnen jetzt zeigen, wie ich das gemacht habe. Also, zuerst einmal habe ich pip install mutmutwas einfach eine Pythonic-Art ist, um Sachen zu installieren, und dann habe ich das ausgeführt. Das war's.
Glücklicherweise gibt es einige sinnvolle Standardeinstellungen, die ich nicht ändern musste. Je nachdem, was Sie tun, müssen Sie vielleicht die Einstellungen ändern. Es gibt verschiedene Konfigurationsoptionen, die Sie wählen können, aber für mich war das in Ordnung. Als ich das Programm startete, sagte es mir im Grunde, was passieren würde. Es wurde also das hier ausgedruckt.
Es druckte die Tatsache aus, dass es zunächst die gesamte Testsuite ausführen würde, um das Timing und solche Dinge zu verstehen. Und dann würde es die Mutanten generieren und sie überprüfen. Es gibt also einige verschiedene Ergebnisse, die sich hier ergeben können. Wir können zum Beispiel eine Mutante fangen, wir können eine Mutante aussetzen lassen, was nicht gut ist, wir können eine haben, die verdächtig aussieht und der wir vielleicht nicht vertrauen, und wir können auch eine haben, die überlebt hat. Und in diesem Fall ist das eine wirklich schlechte Situation, in der wir wissen, dass wir den Mutanten nicht erwischt haben. Als ich das hier durchführte, sahen wir zunächst, dass meine Testsuite lief und dann diese Mutanten überprüft wurden, und wir konnten sehen, dass ich 512 von ihnen erwischte, aber 170 von ihnen nicht. Überlegen Sie sich das einmal.
Ist das eine gute oder eine schlechte Number? Darüber reden wir später, aber jetzt wollen wir uns erst einmal ein paar Mutanten ansehen. Hier ist also ein einfacher, den wir fangen können. Wir haben mit dieser Klasse angefangen. Dies ist unsere Messages API-Klasse.
Wir haben einige gültige Nachrichtenkanäle, über die wir Nachrichten senden können. Und der Mutant hat gerade einen dieser Kanäle geändert. Er hat einfach eine der Zeichenketten geändert. Wir waren also nicht mehr in der Lage, Nachrichten per SMS zu versenden. Ein entsprechender Test schlug also fehl, und das ist großartig.
Das heißt, wir nennen das. Hier ist ein weiteres Beispiel. Ich weiß nicht, ob die Leute, die das hier sehen, Pydantic benutzt haben, aber Pydantic ist eine großartige Validierungsbibliothek, und wir benutzen sie im SDK. Hier ist ein Beispiel, bei dem wir einen Validator haben, das ist Pydantic V1, das ist etwas, das eine Zahl aufrundet. Aber die veränderte Version hat diese Annotation, diesen Dekorator (je nach Sprache werden Sie ihn anders nennen, wir nennen sie in Python Dekoratoren) entfernt.
Also haben wir das entfernt. Und das bedeutete, dass dieser Code nie aufgerufen werden würde. Wenn ich also einen Test zum Runden einer Zahl hatte, wurde dieser nie aufgerufen. Auch das schlug fehl. Das ist gut, denn es bedeutet, dass es zwei Versionen der Codebasis gibt, zwei kleine Henries, die wir abfangen und sagen konnten: "Hey, du bist ein Pinguin, das ist es, was wir brauchen.
Wie sehen wir also die Mutanten? Nun, wenn Sie das tun mutmut showaufruft, kann man eine Liste von ihnen sehen. Und Sie können zum Beispiel den Namen 1, also Nummer 1 anzeigen, die erste Mutante anzeigen und diese sehen. In unserem Fall ändert Nummer 1 zum Beispiel den Authentifizierungstyp, und das war natürlich leicht zu erkennen. Aber das wirklich Interessante ist, dass wir die Ergebnisse all dieser Tests sehen können.
Wir haben also einen Bericht im HTML-Format. Je nachdem, welche Sprache Sie sprechen und welche Software Sie zum Testen von Mutationen verwenden, ist es einfacher oder schwieriger, dies zu tun. Für uns ist es eine recht einfache Schnittstelle, aber im Wesentlichen zeigt sie Ihnen alle Mutanten, die Sie in jeder Datei nicht erwischt haben. Schauen wir uns also einige an.
Hier ist Mutant 58, den wir nicht erwischt haben, und Sie werden sehen, dass nicht alle von ihnen gleich sind. Wie Sie sehen können, haben wir bei dieser Mutante lediglich den Logger umbenannt. Und ich denke, dass die Protokollierung nicht in meinen Tests enthalten ist. Also ist es mir egal, dass diese Mutante reingekommen ist, das war okay, denn ich denke nicht, dass ich das testen sollte.
Das ist also in Ordnung. Hier ist also ein weiteres Beispiel. Das ist Mutant 62. Hier ändern wir nur den Wert einer Konstante. Und noch einmal, ich glaube nicht, dass dies in den Bereich dessen fällt, was ich testen möchte.
Ich glaube nicht, dass es für mich wichtig ist, zu testen, ob ein Standardwert gesetzt ist oder nicht. Das ist für mich in diesem Zusammenhang nicht wichtig. Aber schauen wir uns eine wichtigere Aufgabe an, die mir wichtig ist. Hier ist also einer. Dies ist Mutant 112.
Und was ich hier mache, ist, dass ich Instanzen aller Klassen für alle von uns verwendeten APIs erstelle. Sie können hier sehen, dass wir eine Voice-Klasse haben. In der mutierten Version erstellen wir keine Voice-Klasse, aber unsere Tests sind immer noch erfolgreich, auch wenn wir keine Klasse für alle unsere Voice-Methoden erstellen. Warum ist das so?
Warum schlagen meine Tests nicht fehl? Woran liegt das? Nun, es stellt sich heraus, dass die Art und Weise, wie wir dies verwenden und wie wir im SDK testen, darin besteht, dass wir nicht einfach die Objekte des Clients aufrufen. Wir haben die Voice API Klasse direkt aufgerufen, aber unsere Benutzer werden sie so aufrufen. Und deshalb sollte ich wahrscheinlich einen Test dafür haben.
Diese Zahl sagt mir also etwas sehr Wichtiges über meinen Code, das die Testqualität verbessern wird, weil ich einen Test für genau diesen Fall schreiben kann, der repräsentativ für das ist, was unsere Benutzer tun werden. Kehren wir also zu dieser Zahl zurück. Dann haben wir eine Menge Mutanten gefangen. Wir haben aber auch nicht sehr viele Mutanten erwischt. Tatsächlich haben wir nur etwa 75 % dieser Mutanten gefangen.
Tatsächlich haben wir etwa 25 % verfehlt. Und die Frage, die ich an Sie habe, lautet: Ist das eine gute Zahl? 75%. Ist das gut? Und wenn Sie das sehen und mit den Schultern zucken, ist das die richtige Antwort.
Das Interessante daran ist, dass 100% keinen Sinn machen! Denn es gibt Fälle, die mich einfach nicht interessieren, richtig? Wie der Logger oder die Konstante, die sich ändert. Das ist mir egal. Es geht mir nicht darum, eine 100%ige Mutationsabdeckung zu erreichen, denn dann habe ich nur das Problem mit der Codeabdeckungsrate genommen und es wieder abstrahiert. Was mich wirklich interessiert, ist, einen guten Einblick in meinen Code zu bekommen, das ist es, was mich wirklich interessiert.
Ich hoffe, ich konnte Sie davon überzeugen, dass Sie sich selbst ein wenig mit Mutationstests beschäftigen möchten. Ich hoffe wirklich, dass ich das getan habe. Aber wenn nicht, dann machen Sie sich keine Sorgen, denn ich werde Ihnen jetzt zeigen, wie Sie mit Mutationstests beginnen können, und das ist so einfach, dass ich denke, dass das jeder tun kann, wenn Sie bereits Tests schreiben. Zuallererst ein paar allgemeine Ratschläge: Beginnen Sie lokal, lassen Sie es zuerst auf Ihrem Rechner laufen. Genau das habe ich getan. Ich habe es einfach lokal auf meinem Rechner laufen lassen und klein angefangen. Wenn Sie eine größere Testbasis haben als ich, wenn Sie eine größere Anzahl von Tests haben, sollten Sie vielleicht mit einer Teilmenge davon beginnen. Vielleicht möchten Sie auch die Leistung optimieren. So können Sie bestimmte Tests, die für Sie nicht relevant sind, ausschließen. Zum Beispiel sind Integrationstests für Sie vielleicht nicht so wichtig.
Alternativ können Sie auch Teile des Codes ausschließen, z. B. wenn Sie einen Teil des Codes automatisch generiert haben, was Sie wahrscheinlich nicht interessiert.
Okay. Wenn Sie also Ihre Maschine abschalten wollen, was Sie vielleicht auch tun werden, dann wird Ihnen dieser Teil wirklich helfen. Zunächst einmal bin ich wirklich glücklich mit diesem Pinguinbild. Ich weiß nicht, warum es in dieser Form existiert, aber ich bin sehr froh, dass es das tut.
Aber warum sollten Sie Ihre Maschine abschalten wollen? Ich werde es Ihnen sagen. Das Testen braucht also einige Zeit. Vielleicht möchten Sie die Ressourcen in der Cloud nutzen, anstatt Ihren eigenen Rechner zu verwenden, wenn Sie eine Testsuite ausführen möchten. Das bedeutet auch, dass Sie sie zu Ihrem CI-System hinzufügen können, was sehr nützlich ist.
Das bedeutet, dass Sie verschiedene Plattformen angeben können, auf denen Sie laufen wollen, verschiedene Betriebssysteme, verschiedene Versionen Ihrer Sprache, verschiedene Versionen Ihres Codes. Lassen Sie mich Ihnen das zeigen. Ich habe Ihnen gesagt, warum das ein Vorteil sein könnte. Lassen Sie mich Ihnen zeigen, was ich gemacht habe und wie ich es gemacht habe.
Ich habe dies auf mein Python-SDK angewendet. Und was ich hier tat, war ich erstellt eine GitHub Aktion. Sie können dies in jedem CI-System tun Sie mögen. Ich verwende GitHub Actions. Ich habe etwas für Mutationstests erstellt - ein sehr, sehr einfaches Stück YAML. Im Wesentlichen kann ich damit manuell auswählen, ob der Mutationstest für meine Testsuite ausgeführt werden soll. Und tatsächlich war es eine Entscheidung, dass ich ihn manuell ausführen muss.
Ich möchte nicht, dass es automatisch ausgeführt wird. Man könnte es auf Push laufen lassen, aber ich habe mich dagegen entschieden. Wenn ich es also ausführe, werden Sie sehen, dass es den Auftrag einfach abschließt. Außerdem wird mir der HTML-Bericht zur Verfügung gestellt. Ich erhalte ihn als Run-Artefakt, das ich herunterladen kann. So kann ich genau sehen, wie meine Tests ablaufen und welche Mutanten nicht abgefangen werden.
Wie mache ich das also? Nun, das ist die wirklich interessante Frage hier. Ich werde Ihnen die YAML zeigen, die ich verwendet habe. Also nochmal, ich benutze GitHub Actions. Das ist das, was ich selbst benutze, aber Sie können dies in jedem CI-System tun, das Sie mögen - es ist nur ein einfaches Skripting. Und ehrlich gesagt, was ich auch sagen würde, ist, dass Sie das SDK, das ich pflege, gerne benutzen können. Der Code ist dort zu finden. Sie können die YAML-Datei nehmen. Und bitte benutzen Sie es selbst, Sie sind herzlich eingeladen. Wenn es Sie dazu bringt, Mutationstests durchzuführen, haben alle gewonnen. Aber wie auch immer, ich zeige Ihnen jetzt die YAML-Datei. Ich erkläre Ihnen, was die einzelnen Teile tun und wie sie funktionieren.
Zunächst einmal können Sie hier sehen, dass wir einen Mutationstest YAML haben. Sie können sehen, dass wir auf Ubuntu laufen. Wir arbeiten nur mit einer Version von Python. Das ist in Ordnung. Wir können hier die verschiedenen Schritte sehen. Wir checken also den Code aus und richten dann Python ein.
Danach installieren wir unsere Abhängigkeiten, aber wir fügen jetzt die Abhängigkeit mutmut. Danach führen wir unseren Mutationstest durch, den wir mit mutmut runund wir verwenden dort 2 Flags. Wir verwenden --no-progresswas im Grunde bedeutet, dass unsere Ausgaben besser aussehen, wenn wir sie in unser CI-System zurücklesen. Und wir benutzen auch den --CI Modus, der uns einen sinnvollen Fehlercode zurückgibt. Ich werde das hervorheben, weil es mein einziger Beitrag zu mutmutwar, aber ich bin trotzdem stolz darauf, also werde ich es erwähnen. Es ist hier tatsächlich sehr nützlich, weil wir sonst keinen vernünftigen Fehlercode erhalten und das führt dazu, dass GitHub Actions fehlschlägt. Sobald wir das getan haben, erhalten wir diese HTML-Ausgabe und laden sie hoch, damit wir sie später von GitHub herunterladen können. Und das war's. Es sind 35 Zeilen, das ist alles, was wir tun, und das ist alles gut.
Welche anderen Bedenken haben wir in Bezug auf CI? Welche anderen Dinge sollten Sie bedenken? Nun, zuallererst sollten Sie über die manuelle oder automatische Auslösung nachdenken. Ich persönlich lasse diese Dinge gerne manuell laufen, weil ich nicht möchte, dass dies Teil eines PR-Prozesses ist, bei dem es eine bestimmte Punktzahl erreichen muss, um genehmigt zu werden.
Ich möchte es ausführen, wenn ich etwas Neues hinzugefügt habe, das etwas verändern könnte, oder wenn ich einen Einblick in meinen Code brauche. Sie können es automatisch ausführen lassen, wenn Sie wollen, aber seien Sie sich bewusst, dass Sie das nicht müssen. Wir wollen nicht einfach wieder Goodharts Gesetz abstrahieren und versuchen, den Mutationswert in eine neue Metrik zu verwandeln, die wir abstrahieren können. Wir wollen auch darüber nachdenken, ob wir auf mehreren Betriebssystemen laufen können. Für meinen Code war das nicht wirklich nötig, weil ich nicht erwarte, dass er sich ausreichend verändert - wir spielen nicht mit dem Betriebssystem. Wir machen eher API-Aufrufe, also ist das für uns keine große Sache. Vielleicht möchten Sie auch mehrere Versionen Ihrer Abhängigkeiten und ähnlicher Dinge ausprobieren, um zu sehen, ob sich auch dort etwas ändert.
Zusammenfassend lässt sich also sagen, dass Mutationstests Ihre Tests testen. Es hilft Ihnen, Goodharts Gesetz zur Codeabdeckung zu übertreffen. Wenn Sie es nutzen wollen, würde ich sagen, fangen Sie klein und lokal an, aber sobald Sie bereit sind, lassen Sie es in einem CI-System laufen, damit Sie diese Dinge asynchron erledigen können und nicht die Zeit und Ressourcen Ihrer Maschine verschwenden. Abschließend möchte ich noch sagen, dass Mutanten wertvoll sind, und sie sind auch wunderbar. Wenn wir an Henry denken und an alles, was er uns gegeben hat, dann kann er zwar nicht fliegen und auch nicht den Code ausführen, den wir brauchen, aber was er getan hat, hat uns so viele Einblicke in unsere Codebasis gegeben, dass er einfach wunderbar ist. Wie ich schon zu Beginn der Präsentation sagte, sollte man keine Angst vor Mutanten haben, sondern sie lieben.
Ich danke Ihnen vielmals. Es war sehr, sehr schön, heute mit Ihnen zu sprechen. Wenn Sie sich mit Fragen an mich wenden möchten, bitte dem Vonage Community Slack beitreten. Wenn Sie sich das Python SDKsehen möchten, können Sie sich das auch gerne ansehen. Und wenn Sie einen Account bei Vonage erstellen ein Konto bei Vonage einrichten und unsere Produkte ausprobieren möchten, finden Sie hier ebenfalls einen Link.
Ich hoffe also, dass diese Dinge für Sie nützlich sind. Vielen Dank, und wir sehen uns ein andermal wieder. Zum Wohl.
Teilen Sie:
Max ist ein Python-Entwickler und Software-Ingenieur, der sich für Kommunikations-APIs, maschinelles Lernen, Entwicklererfahrung und Tanz interessiert! Er hat Physik studiert, aber jetzt arbeitet er an Open-Source-Projekten und stellt Dinge her, die das Leben von Entwicklern verbessern.