Testcode-Abdeckung Vom Mythos zur Realität

Es gab eine Zeit, in der Programmierer mit der Anzahl der Codezeilen bezahlt wurden, die sie geschrieben hatten. Sie wurden als quellcodeproduzierende Maschinen behandelt, die in Kabinen arbeiteten, und im Gegenzug überlegten sie, nur eine Arbeit zu programmieren, die sie acht Stunden am Tag erledigen, und dann den Rest des Tages vergessen.

Aber die Zeiten haben sich geändert. Die meisten Kabinenarbeitsplätze verschwanden und die Programmierer liebten ihr Handwerk. Mit dem Aufkommen agiler Techniken und der Software-Handwerkskunstbewegung entstanden viele neue Werkzeuge, die dem Programmierer und dem Prozess helfen. TDD wird langsam zur de facto Art, Code zu schreiben, und die Geheimnisse von SCRUM oder Kanban wurden selbst den Programmierern in den dunkelsten Winkeln der Welt der Kabinen offenbart.

Automatisiertes Testen und testgesteuerte Entwicklung (TDD) sind einige der wichtigsten Techniken, die Agile uns Programmierern zur Verfügung stellt. Ein Tool, das mit diesen Methoden geliefert wird, wird verwendet, um Testcodeabdeckung zu erstellen, die das Thema dieses Artikels ist.

Definition

"In der Informatik ist die Codeabdeckung ein Maß, mit dem beschrieben wird, bis zu welchem ​​Grad der Quellcode eines Programms von einer bestimmten Testsuite getestet wird." ~ Wikipedia

Die obige Definition aus Wikipedia ist eine der einfachsten Methoden, um die Bedeutung der Codeabdeckung zu beschreiben. Grundsätzlich verfügen Sie in Ihrem Projekt über eine Reihe von Produktionscode sowie über eine Reihe von Testcode. Der Testcode führt den Produktionscode aus, und die Testabdeckung gibt an, wie viel von Ihrem Produktionscode von den Tests ausgeübt wurde.

Informationen können auf verschiedene Arten dargestellt werden, von einfachen Prozentsätzen über schöne Grafiken bis hin zu Echtzeit-Hervorhebungen in Ihrer bevorzugten IDE.

Lassen Sie uns es in Aktion überprüfen

Wir werden PHP als Sprache verwenden, um unseren Code zu veranschaulichen. Zusätzlich benötigen wir PHPUnit und XDebug, um unseren Code zu testen und Abdeckungsdaten zu sammeln.

Der Quellcode

Hier ist der Quellcode, den wir verwenden werden. Sie finden es auch im beigefügten Archiv.

Klasse WordWrap public function wrap ($ string = ", $ cols) $ string = trim ($ string); if (strlen ($ string)> $ cols) $ lastSpaceIndex = strrpos (substr ($ string, 0, $ Spalten), "); if ($ lastSpaceIndex! == false && substr ($ string, $ cols, 1)! = ") gibt substr ($ string, 0, $ lastSpaceIndex) zurück." \ n ". $ this-> wrap (substr ($ string, $ lastSpaceIndex), $ cols); else return substr ($ string, 0, $ cols). "\ n". $ this-> wrap (substr ($ string, $ cols), $ cols);  Rückgabe von $ string;

Der obige Code enthält eine einfache Funktion, die den Text pro Zeile in eine bestimmte Anzahl von Zeichen einfügt.

Der Testcode

Wir haben diesen Code mit Hilfe von Test Driven Development (TDD) geschrieben und haben eine 100% ige Codeabdeckung. Das bedeutet, dass wir beim Durchführen unseres Tests jede Zeile des Quellcodes ausüben.

required_once __DIR__. '/… /WordWrap.php'; Klasse WordWrapTest erweitert PHPUnit_Framework_TestCase function testItCanWrap () $ w = new WordWrap (); $ this-> assertEquals (", $ w-> wrap (null, 0)); $ this-> assertEquals (", $ w-> wrap (", 0)); $ this-> assertEquals ('a', $ w-> wrap ('a', 1)); $ this-> assertEquals ("a \ nb", $ w-> wrap ('a b', 1)); $ this-> assertEquals ("ab \") nc ", $ w-> wrap ('ab c', 3)); $ this-> assertEquals (" a \ nbc \ nd ", $ w-> wrap ('a bc d', 3));

Ausführen der Tests in CLI mit Nur-Text-Abdeckung

Eine Möglichkeit, Abdeckungsdaten zu erhalten, besteht darin, unsere Tests in der CLI (Befehlszeilenschnittstelle) auszuführen und die Ausgabe zu analysieren. Für dieses Beispiel gehen wir von einem UNIX-ähnlichen Betriebssystem aus (Linux, MacOS, FreeBSD usw.). Windows-Benutzer müssen die Pfade und Namen der ausführbaren Dateien ein wenig anpassen, sie sollten jedoch ziemlich ähnlich sein.

Öffnen wir eine Konsole und wechseln Sie die Verzeichnisse in Ihre Prüfung Mappe. Dann renne phpunit mit einer Option zum Erzeugen von Abdeckungsdaten als Nur-Text.

phpunit --coverage-text =. / coverage.txt ./WordWrapTest.php

Auf den meisten Systemen sollte dies sofort funktionieren, wenn XDebug installiert ist. In einigen Fällen kann jedoch ein Fehler in Bezug auf Zeitzonen auftreten.

PHP Warning: date (): Es ist nicht sicher, sich auf die Zeitzoneneinstellungen des Systems zu verlassen. Sie sind * erforderlich *, um die Einstellung date.timezone oder die Funktion date_default_timezone_set () zu verwenden. Falls Sie eine dieser Methoden verwendet haben und diese Warnung immer noch angezeigt wird, haben Sie wahrscheinlich die Zeitzonen-ID falsch geschrieben. Wir haben vorerst die Zeitzone 'UTC' ausgewählt, aber stellen Sie mit date.timezone Ihre Zeitzone ein. in phar: ///usr/share/php/phpunit/phpunit.phar/ PHP_CodeCoverage-1.2.10 / PHP / CodeCoverage / Report / Text.php in Zeile 124 

Dies kann leicht durch Angabe der vorgeschlagenen Einstellung in Ihrem behoben werden php.ini Datei. Sie können den Weg finden, um Ihre Zeitzone in dieser Liste anzugeben. Ich komme aus Rumänien und verwende folgende Einstellung:

date.timezone = Europa / Bukarest

Nun, wenn Sie das ausführen phpunit Befehl erneut, sollten Sie keine Fehlermeldungen sehen. Stattdessen werden die Testergebnisse angezeigt.

PHPUnit 3.7.20 von Sebastian Bergmann… Zeit: 0 Sekunden, Speicher: 5.00 MB OK (2 Tests, 7 Assertions) 

Die Abdeckungsdaten befinden sich in der angegebenen Textdatei.

$ cat ./coverage.txt Bericht über die Abdeckung des Codes 2014-03-02 13:48:11 Zusammenfassung: Klassen: 100.00% (1/1) Methoden: 100.00% (1/1) Zeilen: 2.68% (14/522) WordWrap Methoden: 100.00% (1/1) Zeilen: 100.00% (7/7) 

Lassen Sie uns dies ein wenig analysieren.

  • Klassen: bezieht sich darauf, wie viele Klassen getestet wurden und wie viele davon abgedeckt wurden. Zeilenumbruch ist unsere einzige Klasse.
  • Methoden: wie bei den Klassen. Wir haben nur unsere wickeln() Methode, sonst nichts.
  • Linien: wie oben, jedoch für Codezeilen. Hier haben wir viele Zeilen, da die Zusammenfassung alle Zeilen von PHPUnit selbst enthält.
  • Dann haben wir für jede Klasse einen Abschnitt. In unserem Fall ist das nur Zeilenumbruch. Jeder Abschnitt verfügt über eigene Methoden und Zeilendetails.

Aufgrund dieser Beobachtungen können wir feststellen, dass unser Code zu 100% von Tests abgedeckt wird. Genau wie erwartet vor der Analyse der Abdeckungsdaten.

HTML-Coverage-Ausgabe generieren

Durch einfaches Ändern eines einfachen Parameters für PHPUnit können wir eine schöne HTML-Ausgabe generieren.

$ mkdir ./coverage $ phpunit --coverage-html ./coverage ./WordWrapTest.php 

Wenn Sie Ihre überprüfen ./ Abdeckung Verzeichnis finden Sie dort viele Dateien. Ich werde die Liste hier nicht einfügen, da sie recht umfangreich ist. Stattdessen zeige ich Ihnen, wie es in einem Webbrowser aussieht.

Dies ist das Äquivalent des Zusammenfassungsabschnitts aus der obigen Textversion. Folgen Sie den vorgeschlagenen Links und sehen Sie weitere Details.

Abdeckung in unserer IDE

Die vorherigen Beispiele waren interessant und sehr nützlich, ob Ihr Code basiert auf einem Remote-Server, auf den Sie nur SHH- oder Web-Zugriff haben. Aber wäre es nicht schön, all diese Informationen in Ihrer IDE zu haben??

Wenn Sie PHPStorm verwenden, ist alles mit einem Klick erreichbar! Wählen Sie diese Option aus, um Ihre Tests mit Abdeckung auszuführen. Alle Informationen werden einfach auf magische Weise angezeigt.

Die Abdeckungsinformationen sind auf verschiedene Weise und an verschiedenen Stellen in Ihrer IDE vorhanden:

  1. Der Prozentsatz der Testabdeckung wird in der Nähe jedes Verzeichnisses und jeder Datei angezeigt.
  2. Im Editor wird beim Bearbeiten von Code links von den Zeilennummern ein grünes oder rotes Rechteck für jede Zeile markiert. Grün steht für getestete Linien, Rot für nicht getestete. Zeilen ohne tatsächlichen Code (leere Zeilen, nur geschweifte Klammern, Klassen- oder Methodendeklarationen) haben keine Markierungen.
  3. Auf der rechten Seite befinden sich Dateibrowser, in denen Sie Dateien schnell nach Deckung durchsuchen und sortieren können.
  4. In der Testausgabe wird eine Textzeile angezeigt, die Sie darüber informiert, dass Code Coverage generiert wurde.

Die Mythen über die Codeabdeckung

Mit einem solch mächtigen Werkzeug in der Hand des Entwicklers und unter der Nase des Managements waren einige Mythen unvermeidlich. Nachdem die Programmierer sich weigerten, von der Anzahl der Codezeilen, die sie schreiben, bezahlt zu werden, oder die Manager erkannten, wie einfach es ist, das System zu spielen, begannen einige von ihnen, Programmierer nach dem Prozentsatz der Code-Abdeckung zu bezahlen. Höhere Codeabdeckung bedeutet, dass der Programmierer vorsichtiger war, richtig? Es ist ein Mythos. Die Codeabdeckung ist kein Maß dafür, wie gut Sie Code schreiben.

Manchmal neigen Programmierer zu der Ansicht, dass Code mit 100% iger Abdeckung keine Fehler enthält. Ein weiterer Mythos. Die Codeabdeckung zeigt lediglich an, dass Sie jede Codezeile getestet haben. Es ist ein Maß für die Anzahl der ausgeübten Linien. Es ist kein Maß für die Anzahl der korrekt implementierten Zeilen. Zum Beispiel haben halb geschriebene Algorithmen mit nur halb definierten Tests immer noch eine Abdeckung von 100%. Dies bedeutet nicht, dass der Algorithmus abgeschlossen ist oder korrekt funktioniert.

Schließlich ist das Spielen des Systems sehr einfach. Wenn Sie TDD verwenden, haben Sie natürlich einen hohen Abdeckungswert. Bei ganzen Projekten ist 100% nicht möglich. Bei kleinen Modulen oder Klassen ist die Abdeckung von 100% jedoch sehr einfach. Nehmen Sie zum Beispiel unseren Quellcode und stellen Sie sich vor, Sie haben überhaupt keine Tests. Was wäre der einfachste Test, um den gesamten Code auszuführen?

function testItCanWrap () $ w = new WordWrap (); $ this-> assertEquals ("a b \ nc", $ w-> wrap ('a b c', 3)); $ this-> assertEquals ("a \ nbc \ nd", $ w-> wrap ('a bc d', 3)); 

Das ist es. Zwei Behauptungen und vollständige Abdeckung. Das wollen wir nicht. Dieser Test ist so weit von beschreibenden und vollständigen, dass es lächerlich ist.

Die Realität über die Codeabdeckung

Die Codeabdeckung ist eine Statusanzeige und keine Einheit zur Messung der Leistung oder Korrektheit.

Die Codeabdeckung gilt für Programmierer, nicht für Manager. Es ist eine Möglichkeit, Probleme in unserem Code zu erkennen. Eine Möglichkeit, alte, ungeprüfte Klassen zu finden. Eine Möglichkeit, Wege zu finden, die von den Tests nicht genutzt werden und zu Problemen führen könnten.

Bei realen Projekten liegt die Abdeckung des Codes immer unter 100%. Eine perfekte Abdeckung zu erreichen, ist nicht möglich, oder wenn dies der Fall ist, ist dies selten ein Muss. Für eine Abdeckung von 98% müssen Sie jedoch 100% anvisieren. Etwas anderes als Ziel zu haben, ist unsinnig.

Hier finden Sie die Codeabdeckung in Synetos StorageOS-Konfigurationsanwendung.

Die Gesamtsumme beträgt nur etwa 35%, aber die Ergebnisse müssen ausgewertet werden. Die meisten Module befinden sich im grünen Bereich mit einer Abdeckung von mehr als 70%. Es gibt jedoch einen einzigen Ordner, Vmware, was den Durchschnitt nach unten zieht. Es ist ein Modul mit vielen Klassen, die nur Definitionen für die Kommunikations-API enthalten. Es gibt keinen Grund, diese Klassen zu testen. Sie wurden automatisch durch vertrauenswürdigen Code generiert. Die Programmierer wissen das und sie wissen, wie sie die Ergebnisse interpretieren sollen. Ein Manager kann darauf bestehen, es zu testen, da es sich um einen roten Balken handelt und es für jemanden verdächtig erscheint, der die internen Details des Projekts nicht kennt. Wäre es sinnvoll, es zu testen? Überhaupt nicht! Es wäre ein sinnloser Test, der kostbare Bauzeiten von zehn Sekunden beanspruchen würde, ohne einen Vorteil zu haben.

Abschließende Gedanken

Hier sind wir also mit der Abdeckung des Codes: Es ist ein großartiges Werkzeug für Programmierer, eine Informationsquelle, um mögliche Probleme aufzuzeigen, eine missverstandene Realität für die meisten Manager und ein weiteres Werkzeug, um die Aktivitäten von Programmierern zu erzwingen und zu messen. Wie bei jedem anderen Tool kann dieses Werkzeug problemlos verwendet und missbraucht werden.