Mutation Testing - Birgit Kratz - podcast episode cover

Mutation Testing - Birgit Kratz

Jan 28, 202522 minEp. 119
--:--
--:--
Listen in podcast apps:

Episode description

In dieser Episode spreche ich mit Birgit Kratz über Mutation Testing im Java-Umfeld. Birgit gibt uns Einblicke in Mutation Testing, wie diese Technik funktioniert und wie man damit die Qualität von Testsuiten bewerten kann, indem absichtlich Fehler (Mutanten) in den Code eingefügt werden. Sie beschreibt den Prozess, die verschiedenen Arten von Mutanten und die Tools, die zur Automatisierung verwendet werden. Zudem diskutieren wir die Herausforderungen und Vorteile dieser Methode sowie die Bedeutung einer funktionierenden Testsuite, bevor Mutation Testing angewendet wird.

Transcript

Hallo und herzlich willkommen zu einer neuen Folge vom Podcast Software Testing. Ich bin euer Host Ritschi und habe euch heute die Mutanten mitgebracht. Bei uns geht es nämlich heute um Mutation Testing und dazu habe ich Birgit Katz eingeladen, die Mutation Testing im Java Umfeld bei sich in den Projekten nutzt. Was es damit auf sich hat, wie man Mutanten tötet und welche Tools dafür zum Einsatz kommen können, darüber haben wir in der heutigen

Folge gesprochen. Viel Spaß beim Hören. Hallo Birgit, schön, dass du da bist. Hallo Ritschi, danke, dass ich hier sein darf. Ja, ich fand es toll. Wir haben uns ja auf der OOP kennengelernt. Genau. Genau, da war ich ja mit dem Podcast-Stand und da kamst du vorbei und dann hast du gesagt Mutation Testing und ich habe gesagt, ja, das Thema brauchen wir unbedingt im Podcast. So,

und da sind wir nun. Eine Expertin für Mutation Testing und jetzt wollen wir natürlich wissen, was ist denn das eigentlich? Mutation Testing, ja, das ist etwas, womit ich meine Tests testen kann. Das Prinzip ist schon sehr alt, schon über 50 Jahre. Das kam mal ursprünglich von einem

Menschen, der Richard Lipton. 1971 hat er das mal in so einem Paper veröffentlicht. Also, wenn ich jetzt zum Beispiel wissen will, wie gut meine Test-Suite ist und ob die Test-Suite, die ich habe, meinen Code gut checkt, dann wäre es doch clever zu sagen, okay, ich baue da mal einen Bug ein in meinen Code und gucke, ob dann meine Test-Suite diesen Bug findet. Zumindest diese, wenn es nicht schon die, die es eh schon drinnen sind, findet.

Ja, also ich habe vorher natürlich eine Test-Suite, die grün ist und wo ich denke, alles super, alles schick und alles ganz toll und jetzt baue ich da mal absichtlich oder unabsichtlich irgendwie in diesen Code einen Bug ein und wenn dann meine Test-Suite diesen Bug findet, dann ist sie ja zumindest für diese Stelle des Codes ganz gut geeignet und wenn nicht, dann habe ich irgendwie ein Problem. Dann habe ich eine Test-Suite und ich kann da Bugs

einbauen und die findet diesen Bug nicht. Ja, das ist die Idee hinter Mutation Testing eigentlich ganz simpel und wie gesagt schon relativ alt, die Idee, aber das Problem ist, erstens muss man ja dann praktisch immer so einen Bug einbauen, dann die Test-Suite wieder laufen lassen, dann den Bug, dann gucken, was passiert, dann den Bug wieder ausbauen, einen anderen Bug einbauen und so weiter und so weiter und das macht man jetzt ja nicht

per Hand, also per händischen Test, das wäre ja viel zu viel Aufwand. Was sind denn das so für typische Bugs, die man da so einbaut oder was, welche Bugs, worum geht es denn da quasi? Das ist so ein bisschen sprachabhängig, welche Bugs man da einbaut oder diese Bugs, die nennen sich nicht Bugs, sondern Mutanten, deswegen Mutation Testing, also Änderungen an meinem Produktionscode. Da gibt es so ganz verschiedene Kategorien und das ist auch ein bisschen sprachabhängig, welche Sprache man

verwendet. Ich komme jetzt aus der Java Welt und da gibt es so Kategorien, dass man irgendwie so Conditional Boundaries, wie sich das nennt, ändert. Also ich habe irgendwo eine größere Abfrage, ist etwas größer als etwas anderes, dann frage ich, dann mache ich praktisch eine Abfrage, ist etwas jetzt größer gleich etwas anderes. Also ich ändere meine Grenzen, die ich da abteste oder

so kleiner wird zu kleiner gleich und so weiter. Dann gibt es so andere Mutatoren, wo ich dann so ganze Conditionals nekiere, also aus einem größeren wird ein kleiner gleich oder aus einem gleich gleich wird ein ungleich und solche Sachen. Also das würde ich sagen, ist jetzt auch noch nicht mal sprachspezifisch. Dann habe ich so Increment Mutatoren, also dass ich aus dem Plus Plus ein Minus Minus mache, wenn ich irgendwas inkrementiere. Also das sind noch so ganz einfache Mutatoren.

Dann habe ich sowas zum Beispiel, in Java gibt es ja diese Void Methoden, also die irgendwas machen, aber nichts zurückgeben, kein Return Code haben und da würde ich einfach einen Mutator haben, der sagt, ich rufe diese Void Methode einfach mal nicht auf und gucke, was passiert. Oder wenn ich irgendwie Objekte zurückgebe, dann gebe ich halt null zurück mal zum Beispiel oder bei Primitiven gebe ich immer null zurück, also Zero oder einen leeren String. Was gibt es noch für Mutatoren?

Ja, also da sind ja Fantasie eigentlich keine Grenzen gesetzt. Also natürlich, wenn ich Plus Plus Operationen habe, dann wird da ein Minus draus oder mal wird durch eine Division ersetzt, also Multiplikation durch Division ersetzt und so weiter. Also da gibt es ganz viele, viele Mutatoren, die man sich ausdenken könnte und wenn man die jetzt alle per Hand anwenden sollte auf seine Codebasis an allen Stellen, dann wäre man glaube ich ziemlich lange beschäftigt.

Und deswegen hat sich irgendwann, wer mal dahingesetzt hat, hat halt zum Beispiel für Java dann ein Framework dafür geschrieben oder eine Library dafür geschrieben, die mir diese Arbeit abnimmt. Diese Library kann ich dann einbinden in meinen Bildprozess zum Beispiel und kann dann diese ganzen Mutatoren praktisch auf meinen Source Code loslassen und diese Library nimmt dann quasi auf, wie sich mein Code dann verhält und protokolliert das. Und dieses Protokoll

kann ich mir dann hinterher angucken und auswerten. Und diese Auswahl der Mutanten, muss ich die dann trotzdem, mache ich die noch manuell oder nach welchen Kriterien? Also was du jetzt an Beispielen gebracht hast, unfassbar viele Möglichkeiten wieder, das ist ja wie wenn ich alles testen möchte, quasi jetzt auf der anderen Seite. Ja, also zum Beispiel in der Java-Welt gibt es ja das Framework PID und das hat schon so eine

Vorauswahl an Mutanten, die es dann in verschiedenen Stufen, Ausbaustufen anwendet. Da gibt es so Basic und weiß nicht genau wie die Namen sind, also Basic, advanced nicht, aber also Basic-Mutatoren, paar mehr und dann gibt es da noch eine Ausbaustufe, wo alle Mutatoren, die das Framework so mitgibt, angewendet werden können. Die kann man aber auch einzeln dann wieder an- und ausschalten,

weil manches ist vielleicht nicht zutreffend für den Source-Code, den man hat. Oder solche Mutation-Tests, die können ja auch durchaus schon mal länger dauern und man braucht vielleicht nicht alle Mutatoren, die so im Angebot sind. Also zumindest dieses PID gibt dann die Möglichkeit, dass man sagen kann, hier ich konfiguriere, welche Mutatoren überhaupt angewendet werden

sollen, auch mal im Code. Wie schon gesagt, solche Mutation-Tests, die können ja sehr, sehr lange dauern, weil praktisch das immer so läuft, dass immer ein Mutant gebildet wird und dann werden alle Tests wieder laufen gelassen und dann wird geguckt, ob mindestens ein Test fehlschlägt. Und wenn dann wirklich mindestens ein Test fehlschlägt, das ist ein gutes Zeichen, das heißt, meine Test-Suite hat diese Mutante gekillt. So ist die Sprache.

Ich muss da immer an die Teenage Mutant Hero Turtles denken aus meiner Kindheit oder an X-Men. Ja, es ist so eine ziemlich martialische Sprache. Also ein Mutant überlebt oder wird getötet. Genau. Und halt den Mutanten zu töten, ist in dem Fall was Gutes. Ich bin nicht so in der Spielewelt verhaftet. Das heißt, ich bin eigentlich dann froh, wenn die Tests fehlschlagen, wenn bei den Mutation-Tests quasi wirklich was passiert. Werden denn da alle ausgeführt oder

wird dann immer nur so ein Teilbereich, auch der das betrifft? Weil ich denke, wenn du sagst, das dauert ja alles sehr lang auch, wenn ich da für jede Mutation alles immer durchführe, dann mache ich eigentlich nichts anderes mehr. Genau. Oder die Library macht nichts anderes. Das hängt so ein bisschen von der Library ab, die ich da im Gebrauch habe. Ich kann jetzt nur für PIDs reden, weil ich ja aus der Herbert-Welt komme und meistens PID anwende.

Da ist es so, dieses Tool ist da schon, was das angeht, sehr optimiert. Also das zeichnet auch auf, wenn es schon mal so Mutation-Tests hat laufen lassen, welche Sachen sind da gelaufen. Und wenn ich dann eine Änderung am Code mache und erneut einen Mutation-Test laufen lasse, dann guckt der, wo hat sich über, welche Tests sind überhaupt von dieser Änderung betroffen und nur die werden dann nochmal quasi durch das Tool geschickt. Also es ist schon sehr, sehr optimiert. Man kann da so

eine History mitschreiben. Da werden so Hashcodes mitgeschrieben, mitprotokolliert vom Code und von den Tests. Und dann wird geguckt, was muss ich überhaupt ausführen, weil wo sich nichts geändert hat, da wird sich das Ergebnis auch nicht ändern. Ja, dann kann ich das ja auch ein bisschen besser in meinen Bildprozess mit einbauen, weil wenn das jedes Mal Stunden dauern würde, wäre das ja gar

nicht sinnvoll. Aber wenn das nur inkrementell läuft, dann habe ich da natürlich mehr Möglichkeiten, das auch in meinen Daily oder in meine laufenden Bilds oder was auch immer mit einzubauen. Und man kann eben oder man sollte eben auch, wenn man Mutation-Testing einführen will, nicht gleich das auf alles anwenden, auf seinen ganzen Source-Code, sondern vielleicht erst mal

auf die Kern-Business-Logik, die man so hat. Also jetzt so UI damit, Mutation zu testen oder so Datenbank zu griffen, das ist vielleicht erst mal Overkill, sondern dass man dann wirklich, man kann diesem Framework dann auch sagen, bitte teste nur, was innerhalb dieser Packages,

um in Java sprech zu bleiben zum Beispiel, ist oder in einer speziellen Klasse. Man kann das dann sehr gut eingrenzen, worauf man überhaupt die Mutation-Tests anwenden will, weil nicht alles ist sinnvoll an der Stelle oder dauert dann auch viel, viel, viel zu lang. Muss ich denn noch eine Analyse machen? Weil ich meine, es kann ja auch sein, dass der Test fehlschlägt, weil was im richtigen Code falsch war oder so. Also

oder gibt es da keine Doppelung? Natürlich. Also diese Mutation-Tests sind ja gut dafür, ARA rauszufinden, sind meine Testdaten gut, mit denen ich teste. Testen die zum Beispiel so Grenzbereiche ab oder fehlt da irgendwas in Testdaten? Es ist zum einen, zum anderen gut herauszufinden, was habe ich noch gar nicht getestet? Und drittens ist es auch gut dafür, irgendwelche überhaupt so Logikprobleme zu finden. Jetzt ändere ich da

was am Code und es schlägt nichts fehl. Dann gucke ich natürlich rein in meinen Code, warum? Ich gucke sowohl in meine Tests als auch in meinen Code und dann kommt manchmal so dieser Aha-Effekt, kann ja nicht, weil da habe ich ja noch einen Fehler drin. Also sowas passiert dann durchaus auch. Ich habe zwar Tests geschrieben und die sind auch grün, aber eigentlich habe ich da irgendwie eine falsche Logik und auch irgendwie was komplett Falsches getestet.

Was sind denn da so deine Erfahrungen, wenn das so immer wieder durchläuft? Kommst du dann wirklich auf neue Testideen? Hast du dann jeden Tag, denkst du dir, ach, wieder zwei neue Testideen, die ich dann auch wieder machen muss? Oder wie gehst du denn damit um und wie häufig tritt das überhaupt auf? Am Anfang hast du dann neue Testideen, ja. Aber je öfter man dieses Mutation Testing oder dieses Tool auch verwendet, ist es natürlich so, dass du auch

selbst einen gewissen Lerneffekt hast. Also du hast dann schon diesen Effekt, dass du beim Schreiben der Tests schon an deine Mutation Tests denkst. Und du kennst ja dann die Mutanten, die da so angewendet werden und kannst dann praktisch schon im Vorhinein darauf reagieren, so im gewissen Sinne. Also du hast so einen gewissen Lerneffekt auch dabei. Wenn man das jetzt zum ersten Mal auf einem Projekt anwendet, wo man vielleicht auch selber den Code nicht

geschrieben hat, kann es erst mal erschlagend sein. Also da sollte man vielleicht so anfangen, dass man nur eine geringe Anzahl Mutanten überhaupt einschaltet und sich dann so langsam vorarbeitet und dann auch die Ergebnisse sich genau anguckt und analysiert und die Tests oder den Code oder beides ändert. Aber je länger man dieses Tool dann anwendet, umso mehr Kenntnis hat man ja dann darüber, welche Mutanten gibt es und was könnte da so passieren.

Was allerdings auch passieren kann bei diesem Mutation Testing zum Beispiel ist, ja dass man sogenannte äquivalente Mutanten bekommt. Also das sind quasi Mutanten, die den Code oder die Logik des Codes nicht wirklich ändern. Also der Code funktioniert hinterher nach der Mutation genauso wie vorher und natürlich schlagen dann meine Tests nicht fehl. Zumindest Pit versucht das zu antizipieren und im Vorhinein zu verhindern, diese äquivalenten

Mutanten, aber sie lassen sich nicht in jedem Fall verhindern. Und diese Stellen muss man dann halt rausfiltern. Kriege ich die überhaupt mit? Also die kriege ich ja ganz schwer mit nur. Ja, es wird ein Mutant erstellt, aber alle Tests sind noch grün und das wird ja gemeldet. Man muss ja andersrum denken. Das muss ja dann fehlschlagen eigentlich. Also wenn es grün bleibt oder sowas, dann habe ich die Gefahr, dass dann einfach auch vielleicht so ein Mutant dann einfach

auch so ein äquivalenter Mutant ist. Aber diese äquivalenten Mutanten sind, sage ich mal, abhängig von dem, was man da programmiert, relativ selten und manchmal kann man den Code auch so umschreiben oder es ist auch ein Hinweis dafür, dass da mein Code vielleicht ein bisschen komisch ist. Genau, das wäre jetzt auch meine Idee gewesen. Dann ist ja vielleicht auch bei der Implementierung einfach was schief gelaufen, wenn ein anderes Konstrukt

da das gleiche Ergebnis bringt. Sowas kann da eben auch passieren. Das ist durchaus gegeben. Also wie gesagt, anfänglich kämpft man manchmal auch ein bisschen mit dem, was passiert da eigentlich und warum sind jetzt keine Tests angeschlagen, also warum ist immer alles nur grün. Aber je öfter man dieses Tool für sich verwendet, vielleicht auch nur oder im Team nachher später auch verwendet, umso mehr lernt man dann so die Sache kennen und vermeidet das

schon im Vorhinein. Also ich habe das ja dann probiert. Ich habe einen Vortrag dazu gemacht und habe da halt auch Beispielcode erstellen wollen. Es ist mir wahnsinnig schwer gefallen, da irgendwie was zu kreieren, was irgendwie fehlschlägt. Weil ja, da muss man sich schon anstrengen, dann nachher, wenn man das Tool ganz gut kennt. Ja genau, du machst jetzt einfach schon

so gute Testfälle, dass das gar nichts mehr passiert. Aber eins wollte ich noch sagen, um Mutation Testing anwenden zu können, brauche ich, die Voraussetzungen dafür sind, ich brauche Tests und diese Tests müssen grün sein. Ja, da sind ja schon zwei Faktoren, bei denen scheitert es manchmal. Also ich habe noch welche und dann sind die noch grün.

So und erst dann kann ich darauf dann quasi Mutation Testing anwenden. Also auch, wenn ich das in meine Build Pipeline einbauen will, dann kommt das immer nach dem Kompilieren und Testen. Und erst wenn die Tests alle grün sind, erst dann kann ich sagen, ja und jetzt

mache bitte auch Mutation Testing drauf. Schaut ihr euch denn solche, die Ergebnisse, die dann da rauskommen, gerade wenn das, also wenn das fehlschlägt, also wenn es nicht fehlschlägt, schaut ihr euch dann sowas im Team auch an, dass ihr mal da auch gemeinsam drüber schaut, um da noch mal ein bisschen Lerneffekt zu haben? Es ist leider so, dass ich, ich bin Freiberuflerin und ich war, ich bin ja in unterschiedlichen Teams. Ich war leider noch nie

in so einem Team, das auch bereit war, da mal einzusteigen. Also wenn, dann mache ich das meistens so für mich. Aber ich kann mir das sehr gut vorstellen, dass wenn man sich dann mal hinsetzt und sagt, hier, wir machen mal so eine Session, wo wir uns die Mutation Findings angucken, Mutation Test Findings angucken, dass das sehr, sehr viel Lerneffekt bringen kann. Ja, das denke ich auch. Also das ist ja, bei mir hat es ja schon gewirkt, warum sollte das dann nicht in einem Team auch

wirken? Aber es ist so, ja, es ist so, teste deine Tests und dann sagen viele ja, teste die Tests, der Test, der Test und so. Also wo soll das denn aufhören? Da kommt dann oft schon so ein, ah, wir brauchen mal nicht. Ja, also ich finde es schon sehr spannend, weil es ja im Prinzip auch, ich sehe das, wenn ich jetzt so, was du erzählt hast, darauf sehe ich das ja eher auch so, als dass das ganze Framework dann auch ein Trainer wird, um, damit man selber bessere

Testfälle schreibt. Und da, das ist, da spart man sich auch viel oder kann einfach die Lernkurve auch eine gute haben, einfach auch bessere Tests zu machen. Also nicht nur bessere Tests, sondern auch besseren Code. Ja, ja, genau, beides, ja. Ja, beides, genau. Ja, sehr schön. Birgit, das finde ich einen klassen Einblick, da mal in das Mutation Testing,

da uns da mal reinzuholen. Das finde ich eine ganz, ganz spannende Sache. Ich danke dir herzlich, dass du da heute hier warst und meine Rede und Antwort gestanden hast zu diesem Thema. Ich habe schon im Vorfeld gesagt, ich habe schon im Vorfeld so Interessenten gehabt, die wollten da schon gleich die Folge haben. Also dann werde ich das gleich weiterleiten. Ich habe es für mich auch jetzt in meinen Fundusglen noch mal aktualisiert. Das ist eine

tolle Sache. Ich danke dir schön, dass du da warst und ich wünsche dir noch alles Gute für die Zukunft und bis bald. Danke und dir noch weiterhin viel Erfolg für deinen Podcast, den ich auch regelmäßig höre. So ist es richtig. Das war nicht abgesprochen, aber das war die richtige Aussage zum Schluss. Dankeschön, mach's gut. Tschüss. Tschüss. Tschüss. Tschüss. [Musik]

Transcript source: Provided by creator in RSS feed: download file