Dieses Paket ist veraltet. Sehen Sie sich stattdessen „Infection“ an.
Humbug ist ein Mutationstest-Framework für PHP. Es befindet sich derzeit in der Entwicklung und obwohl es eigentlich ganz gut funktioniert, wird es Ecken und Kanten haben, an deren Beseitigung ein Team von Schergen hart arbeitet. Wenn es aus dem Tor fällt, sind Sie gewarnt ;).
$ git remote set-url upstream https://github.com/humbug/humbug.git
Ersetzen Sie upstream
durch den Namen der Fernbedienung, die Sie lokal verwenden. upstream
wird häufig verwendet, aber möglicherweise verwenden Sie etwas anderes. Sie können auch eine andere URL verwenden (z. B. [email protected]:mockery/mockery.git). Führen Sie git remote -v
aus, um zu sehen, was Sie tatsächlich verwenden.
Inhaltsverzeichnis
Mutationstests bedeuten kurz gesagt, dass Ihre Unit-Tests auf die Probe gestellt werden. Dabei werden kleine Fehler in den Quellcode eingefügt und anschließend überprüft, ob die Unit-Tests dies bemerkt haben. Wenn dies der Fall ist, haben Ihre Unit-Tests die Mutation „getötet“. Wenn nicht, ist die Mutation der Entdeckung entgangen. Da Unit-Tests dazu gedacht sind, Regressionen zu verhindern, wäre es eine schlechte Sache, wenn eine echte Regression unbemerkt durchgeht!
Während Code Coverage Ihnen sagen kann, welchen Code Ihre Tests ausführen, soll Mutation Testing Ihnen dabei helfen, zu beurteilen, wie gut Ihre Unit-Tests tatsächlich funktionieren und wo sie verbessert werden könnten.
Ich habe ausführlicher darüber geschrieben, warum sich Mutationstests lohnen: Lies, Damned Lies and Code Coverage: Towards Mutation Testing
Humbug ist ein Open-Source-Projekt, das Pull-Anfragen und -Probleme von jedem willkommen heißt. Bevor Sie Pull Requests öffnen, lesen Sie bitte unseren kurzen Beitragsleitfaden.
Sie können die Abhängigkeiten von Humbug mit Composer klonen und installieren:
git clone https://github.com/humbug/humbug.git
cd humbug
/path/to/composer.phar install
Der Humbug-Befehl befindet sich jetzt unter bin/humbug.
Wenn Sie den Hauptzweig nicht direkt verfolgen möchten, können Sie den Humbug-Phar wie folgt installieren:
wget https://padraic.github.io/humbug/downloads/humbug.phar
wget https://padraic.github.io/humbug/downloads/humbug.phar.pubkey
# If you wish to make humbug.phar directly executable
chmod +x humbug.phar
Unter Windows können Sie den Download einfach über einen Browser oder von Powershell v3 mit den folgenden Befehlen durchführen, wobei wget
ein Alias für Invoke-WebRequest
ist:
wget https://padraic.github.io/humbug/downloads/humbug.phar -OutFile humbug.phar
wget https://padraic.github.io/humbug/downloads/humbug.phar.pubkey -OutFile humbug.phar.pubkey
Wenn Sie mit Powershell v2 nicht weiterkommen:
$client = new-object System.Net.WebClient
$client .DownloadFile( " https://padraic.github.io/humbug/downloads/humbug.phar " , " humbug.phar " )
$client .DownloadFile( " https://padraic.github.io/humbug/downloads/humbug.phar.pubkey " , " humbug.phar.pubkey " )
Der Phar ist mit einem privaten OpenSSL-Schlüssel signiert. Um sie verwenden zu können, muss die Pubkey-Datei jederzeit neben der Phar-Datei gespeichert sein. Wenn Sie beispielsweise humbug.phar
in humbug
umbenennen, benennen Sie auch den Schlüssel von humbug.phar.pubkey
in humbug.pubkey
um.
Die Phar-Releases werden derzeit manuell erstellt, sodass sie nicht mit der gleichen Häufigkeit wie Git Master aktualisiert werden. Um Ihren aktuellen Phar zu aktualisieren, führen Sie einfach Folgendes aus:
./humbug.phar self-update
Hinweis: Die Verwendung eines Phar bedeutet, dass es möglicherweise länger dauert, bis Korrekturen Ihre Version erreichen, aber es besteht mehr Sicherheit, dass Sie über eine stabile Entwicklungsversion verfügen. Der öffentliche Schlüssel wird nur einmal heruntergeladen. Es wird von Self-Update wiederverwendet, um zukünftige Phar-Releases zu überprüfen.
Sobald die Veröffentlichungen in Richtung stabiler Versionen beginnen, wird es eine Alpha-, Beta-, RC- und eine endgültige Veröffentlichung geben. Die Phar-Datei Ihres Entwicklungstracks wird automatisch aktualisiert, bis eine stabile Version erreicht ist. Wenn Sie weiterhin die Entwicklungsstufen-PHARs verfolgen möchten, müssen Sie dies mithilfe eines der Stabilitätsflags angeben:
./humbug.phar self-update --dev
Wenn bei der Selbstaktualisierung Probleme mit unerwarteten openssl
oder SSL-Fehlern auftreten, stellen Sie bitte sicher, dass Sie die openssl
Erweiterung aktiviert haben. Unter Windows können Sie dies tun, indem Sie die folgende Zeile in der Datei php.ini
für PHP in der Befehlszeile hinzufügen oder auskommentieren (falls sie von der Datei für Ihren http-Server abweicht):
extension=php_openssl.dll
Bestimmte andere SSL-Fehler können aufgrund fehlender Zertifikate auftreten. Sie können dies beheben, indem Sie ihren Speicherort auf Ihrem System ermitteln (z. B. C:/xampp/php/ext/cacert.pem
) oder alternativ eine Kopie von http://curl.haxx.se/ca/cacert.pem herunterladen. Stellen Sie dann sicher, dass die folgende Option korrekt auf diese Datei verweist:
openssl.cafile=C:/path/to/cacert.pem
Da die Abhängigkeiten von Humbug an neuere Versionen gebunden sind, kann das Hinzufügen von Humbug zu Composer.json zu Konflikten führen. In diesem Fall werden die beiden oben genannten Installationsmethoden bevorzugt. Sie können es jedoch global wie jedes andere Allzweck-Tool installieren:
composer global require ' humbug/humbug=~1.0@dev '
Und wenn Sie dies noch nicht getan haben ... fügen Sie dies zu ~/.bash_profile
(oder ~/.bashrc
) hinzu:
export PATH= ~ /.composer/vendor/bin: $PATH
Humbug funktioniert derzeit auf PHP 5.4 oder höher.
Humbug befindet sich noch in der Entwicklung, also seien Sie vorsichtig mit Ecken und Kanten.
Um Humbug in Ihrem Projekt zu konfigurieren, können Sie Folgendes ausführen:
humbug configure
Dieses Tool stellt einige Fragen, die zum Erstellen der Humbug-Konfigurationsdatei ( humbug.json.dist
) erforderlich sind.
Erstellen Sie im Basisverzeichnis Ihres Projekts eine Datei humbug.json.dist
:
{
"timeout" : 10 ,
"source" : {
"directories" : [
"src"
]
} ,
"logs" : {
"text" : "humbuglog.txt" ,
"json" : "humbuglog.json"
}
}
Sie können die humbug.json.dist
in Ihr VCS übernehmen und sie lokal mit einer Datei humbug.json
überschreiben.
Bearbeiten Sie es entsprechend. Wenn Sie nicht mindestens ein Protokoll definieren, sind keine detaillierten Informationen zu entkommenen Mutanten verfügbar. Das Textprotokoll ist für Menschen lesbar. Wenn Quelldateien im Basisverzeichnis vorhanden sind oder Dateien in den Quellverzeichnissen ausgeschlossen werden müssen, können Sie Ausschlussmuster hinzufügen (hier eines für Dateien im Basisverzeichnis, bei dem Composer-Anbieter- und Testverzeichnisse ausgeschlossen sind):
{
"timeout" : 10 ,
"source" : {
"directories" : [
"."
] ,
"excludes" : [
"vendor" ,
"Tests"
]
} ,
"logs" : {
"text" : "humbuglog.txt"
}
}
Wenn Sie vom Basisverzeichnis Ihres Projekts aus Tests aus einem anderen Verzeichnis ausführen müssen, können Sie dies ebenfalls signalisieren. Sie sollten Humbug in keinem anderen Verzeichnis als dem Basisverzeichnis Ihres Projekts ausführen müssen.
{
"chdir" : "tests" ,
"timeout" : 10 ,
"source" : {
"directories" : [
"src"
] ,
}
}
Stellen Sie sicher, dass alle Ihre Tests bestanden sind (unvollständige und übersprungene Tests sind zulässig). Humbug wird beendet, wenn einer Ihrer Tests fehlschlägt.
Der magische Befehl im Basisverzeichnis Ihres Projekts (mithilfe des PHAR-Downloads) lautet:
./humbug.phar
oder wenn Sie gerade Humbug geklont haben:
../humbug/bin/humbug
oder wenn Sie Humbug als Composer-Abhängigkeit zu Ihrem Projekt hinzugefügt haben:
./vendor/bin/humbug
Anstelle von PHP mit der xdebug-Erweiterung können Sie Humbug auch über phpdbg ausführen:
phpdbg -qrr humbug.phar
Wenn alles gut gelaufen ist, erhalten Sie etwas Ähnliches wie:
_ _ _
| || |_ _ _ __ | |__ _ _ __ _
| __ | || | ' | '_ || / _` |
|_||_|_,_|_|_|_|_.__/_,___, |
|___/
Humbug version 1.0-dev
Humbug running test suite to generate logs and code coverage data...
361 [==========================================================] 28 secs
Humbug has completed the initial test run successfully.
Tests: 361 Line Coverage: 64.86%
Humbug is analysing source files...
Mutation Testing is commencing on 78 files...
(.: killed, M: escaped, S: uncovered, E: fatal error, T: timed out)
.....M.M..EMMMMMSSSSMMMMMSMMMMMSSSE.ESSSSSSSSSSSSSSSSSM..M.. | 60 ( 7/78)
...MM.ES..SSSSSSSSSS...MMM.MEMME.SSSS.............SSMMSSSSM. | 120 (12/78)
M.M.M...TT.M...T.MM....S.....SSS..M..SMMSM...........M...... | 180 (17/78)
MM...M...ESSSEM..MMM.M.MM...SSS.SS.M.SMMMMMMM..SMMMMS....... | 240 (24/78)
.........SMMMSMMMM.MM..M.SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS | 300 (26/78)
SSSSSSSSM..E....S......SS......M.SS..S..M...SSSSSSSS....MMM. | 360 (37/78)
.M....MM..SM..S..SSSSSSSS.EM.S.E.M............M.....M.SM.M.M | 420 (45/78)
..M....MMS...MMSSS................M.....EME....SEMS...SSSSSS | 480 (52/78)
SSSSS.EMSSSSM..M.MMMM...SSE.....MMM.M..MM..MSSSSSSSSSSSSSSSS | 540 (60/78)
SSS....SSSSSSSSMM.SSS..........S..M..MSSMS.SSSSSSSSSSSSSSSSS | 600 (68/78)
......E...M..........SM.....M..MMMMM.MMMMMSSSSSSSM.SS
653 mutations were generated:
284 mutants were killed
218 mutants were not covered by tests
131 covered mutants were not detected
17 fatal errors were encountered
3 time outs were encountered
Metrics:
Mutation Score Indicator (MSI): 47%
Mutation Code Coverage: 67%
Covered Code MSI: 70%
Remember that some mutants will inevitably be harmless (i.e. false positives).
Humbug results are being logged as JSON to: log.json
Humbug results are being logged as TEXT to: log.txt
Um die vielleicht kryptische Fortschrittsausgabe zu erklären:
Kills, Fehler und Timeouts werden alle als erkannte Mutationen gezählt. Wir melden Fehler in den Protokollen, wenn Humbug selbst auf einen internen Fehler gestoßen ist, z. B. einen Fehler, der hier als Problem gemeldet werden soll!
Die Beispielzusammenfassungsergebnisse ergaben eine Reihe von Metrikbewertungen:
Wenn Sie diese Kennzahlen untersuchen, fällt auf, dass der MSI von 47 % 18 Punkte niedriger ist als die gemeldete Codeabdeckung von 65 %. Diese Unit-Tests sind weitaus weniger effektiv, als die Code-Abdeckung allein erkennen könnte.
Die Interpretation dieser Ergebnisse erfordert einen gewissen Kontext. In den Protokollen werden alle nicht erkannten Mutationen als Unterschiede zum ursprünglichen Quellcode aufgeführt. Die Untersuchung dieser Mutationen wird weitere Erkenntnisse darüber liefern, welche spezifischen Mutationen unentdeckt geblieben sind.
Humbug verfügt über einige bemerkenswerte Befehlszeilenoptionen, die sich von denen unterscheiden, die normalerweise mit jeder Symfony-Konsolenanwendung verbunden sind.
Sie können den Timeout-Schwellenwert für jeden einzelnen Test manuell festlegen:
humbug --timeout=10
Wenn Sie nur daran interessiert sind, eine Teilmenge Ihrer Dateien zu verändern, können Sie eine beliebige Anzahl von --file
Optionen übergeben, die einfache Dateinamen, Globs oder reguläre Ausdrücke enthalten. Im Grunde werden diese alle an die name()
-Methode des Symfony Finders übergeben.
humbug --file=NewClass.php --file= * Driver.php
Dies schränkt in keiner Weise die anfängliche Humbug-Prüfung der gesamten Testsuite ein, die weiterhin vollständig ausgeführt wird, um sicherzustellen, dass alle Tests korrekt verlaufen, bevor fortgefahren wird.
Wenn Sie nur einige bestimmte Dateien mutieren möchten, können Sie eine beliebige Anzahl von --path
Optionen übergeben, die vollständige Pfaddateinamen enthalten. Diese Option wird an einen Filter Closure
übergeben, der Dateien, die mit der Option „config“ und/oder --file
gefunden wurden, mit den Dateien vergleicht, die Sie mit der Option --path
bereitgestellt haben.
humbug --path=src/Data/NewClass.php --path=src/Driver/Driver.php
Hinweis: Dies schränkt in keiner Weise die anfängliche Humbug-Prüfung der gesamten Testsuite ein, die weiterhin vollständig ausgeführt wird, um sicherzustellen, dass alle Tests korrekt verlaufen, bevor fortgefahren wird.
Inkrementelle Analyse (IA) ist ein experimenteller, unvollendeter Betriebsmodus, bei dem Ergebnisse zwischen Durchläufen lokal zwischengespeichert und dort wiederverwendet werden, wo es sinnvoll ist. Derzeit funktioniert dieser Modus sehr naiv, indem er Testläufe eliminiert, bei denen sowohl die unmittelbar zu mutierende Datei als auch die relevanten Tests für eine mutierte Zeile seit dem letzten Lauf nicht geändert wurden (wie durch Vergleich des SHA1 der beteiligten Dateien bestimmt).
humbug --incremental
Der IA-Modus bietet eine erhebliche Leistungssteigerung für relativ stabile Codebasen, und Sie können ihn jederzeit testen und sehen, wie er im wirklichen Leben abschneidet. Zukünftig müssen Änderungen in Dateien berücksichtigt werden, die übergeordnete Klassen, importierte Merkmale und die Klassen ihrer unmittelbaren Abhängigkeiten enthalten, die sich alle auf das Verhalten eines bestimmten Objekts auswirken.
IA verwendet einen lokalen permanenten Cache, z. B. /home/padraic/.humbug
.
Mutationstests waren traditionell langsam. Das Konzept besteht darin, Ihre Testsuite für jede generierte Mutation erneut auszuführen. Um die Sache deutlich zu beschleunigen, geht Humbug wie folgt vor:
Obwohl all dies die Geschwindigkeit von Humbug beschleunigt, sollten Sie sich darüber im Klaren sein, dass ein Humbug-Lauf langsamer ist als Unit-Tests. Eine 2-Sekunden-Testfolge kann für Mutationstests 30 Sekunden erfordern. Oder 5 Minuten. Es hängt alles vom Zusammenspiel zwischen den Codezeilen, der Anzahl der Tests, dem Grad der Codeabdeckung und der Leistung von Code und Tests ab.
Humbug implementiert eine grundlegende Reihe von Mutatoren, die uns im Wesentlichen sagen, wann ein bestimmter PHP-Token mutiert werden kann, und diese Mutation auch auf ein Array von Token anwenden.
Hinweis: Der in Funktionen (und nicht in Klassenmethoden) enthaltene Quellcode ist derzeit nicht mutiert.
Binäre Arithmetik:
Original | Mutiert | Original | Mutiert |
---|---|---|---|
+ | - | /= | *= |
- | + | %= | *= |
* | / | **= | /= |
/ | * | & | | |
% | * | | | & |
** | / | ^ | & |
+= | -= | ~ | |
-= | += | >> | << |
*= | /= | << | >> |
Boolesche Substitution:
Dies umfasst vorübergehend logische Mutatoren.
Original | Mutiert |
---|---|
WAHR | FALSCH |
FALSCH | WAHR |
&& | || |
|| | && |
Und | oder |
oder | Und |
! |
Bedingte Grenzen:
Original | Mutiert |
---|---|
> | >= |
< | <= |
>= | > |
<= | < |
Negierte Bedingungen:
Original | Mutiert | Original | Mutiert |
---|---|---|---|
== | != | > | <= |
!= | == | < | >= |
<> | == | >= | < |
=== | !== | <= | > |
!== | === |
Schritte:
Original | Mutiert |
---|---|
++ | -- |
-- | ++ |
Rückgabewerte:
Original | Mutiert | Original | Mutiert |
---|---|---|---|
return true; | return false; | return 1.0>; | return -( + 1); |
return false; | return true; | return $this; | null zurückgeben; |
0 zurückgeben; | Rückgabe 1; | Rückgabefunktion(); | Funktion(); null zurückgeben; |
zurückkehren ; | 0 zurückgeben; | neue Klasse zurückgeben; | neue Klasse; null zurückgeben; |
Rückgabe 0,0; | Rückgabe 1,0; | return ( Anything ); | ( Anything ); null zurückgeben; |
Rückgabe 1,0; | Rückgabe 0,0; |
Literale Zahlen:
Original | Mutiert |
---|---|
0 | 1 |
1 | 0 |
Int > 1 | Int + 1 |
Float >= 1 / <= 2 | Float + 1 |
Float > 2 | 1 |
If-Anweisungen:
Alle if-Anweisungen werden weitgehend von früheren Mutatoren abgedeckt, es gibt jedoch Sonderfälle wie die Verwendung nativer Funktionen oder Klassenmethoden ohne Vergleiche oder Operationen, z. B. is_int()
oder in_array()
. Dies würde nicht die in Dateien definierten Funktionen abdecken, da diese erst zur Laufzeit existieren (etwas anderes, an dem man arbeiten kann!).
Original | Mutiert |
---|---|
if(is_int(1)) | if(!is_int(1)) |
Im Laufe der Zeit werden weitere Mutatoren hinzugefügt.
bin/humbug stats ../my-project/humbuglog.json ../my-project/list-of-classes.txt --skip-killed=yes [-vvv]
Analysiert Statistiken aus humbuglog.json oder Ihrem benutzerdefinierten JSON-Protokoll.
CLI-Referenz:
humbug stats [humbuglog.json location] [class list location] [--skip-killed = yes] [-vvv]
humbuglog.json location, defaults to ./humbuglog.json
class list location, a path to a text file containing full class names, one per line.
only this files-related stats would be shown
--skip-killed=yes is used to completely skip output of "killed" section
various verbosity levels define amount of info to be displayed:
by default, there's one line per class with amount of mutants killed/escaped/errored/timed out (depending on output section)
-v adds one line per each mutant with line number and method name
-vv adds extra line for each mutant, displaying diff view of line mutant is detected in
-vvv shows full diff with several lines before and after
Dies kann auf Humbug selbst getestet werden, indem es im Humbug-Verzeichnis ausgeführt wird:
Bin/Humbug Bin/Humbug-Statistiken [-vvv]
Dies ist eine kurze Liste bekannter Probleme:
Mit freundlicher Genehmigung von Craig Davis, der Potenzial in einem einst leeren Depot erkannte :P.
.:::::::::::...
.::::::::::::::::::::.
.::::::::::::::::::::::::.
::::::::::::::::::::::::::::.
::::::::::::::::::::::::::::::: .,uuu ...
:::::::::::::::::::::::::::::::: dHHHHHLdHHHHb
....:::::::'` ::::::::::::::::::' uHHHHHHHHHHHHHF
.uHHHHHHHHH' ::::::::::::::`. uHHHHHHHHHHHHHP"
HHHHHHHHHHH `:::::::::::',dHHuHHHHHHHHP".g@@g
J"HHHHHHHHHP 4H ::::::::' u$$$.
".HHHHHHHHP" .,uHP :::::' uHHHHHHHHHHP"",e$$$$$c
HHHHHHHF' dHHHHf `````.HHHHHHHHHHP",d$$$$$$$P%C
.dHHHP"" JHHHHbuuuu,JHHHHHHHHP",d$$$$$$$$$e=,z$$$$$$$$ee..
"" .HHHHHHHHHHHHHHHHHP",gdP" ..3$$$Jd$$$$$$$$$$$$$$e.
dHHHHHHHHHHHHHHP".edP " .zd$$$$$$$$$$$"3$$$$$$$$c
`???""??HHHHP",e$$F" .d$,?$$$$$$$$$$$$$F d$$$$$$$$F"
?be.eze$$$$$".d$$$$ $$$E$$$$P".,ede`?$$$$$$$$
4."?$$$$$$$ z$$$$$$ $$$$r.,.e ?$$$$ $$$$$$$$$
'$c "$$$$ .d$$$$$$$ 3$$$.$$$$ 4$$$ d$$$$P"`,,
"""- "$$".`$$" " $$f,d$$P".$$P zeee.zd$$$$$.
ze. .C$C"=^" ..$$$$$$P".$$$'e$$$$$P?$$$$$$
.e$$$$$$$"="$f",c,3eee$$$$$$$$P $$$P'd$$$$"..::.."?$%
4d$$$P d$$$dF.d$$$$$$$$$$$$$$$$f $$$ d$$$" :::::::::.
$$$$$$ d$$$$$ $$$$$$$$$$$$$$$$$$ J$$",$$$'.::::::::::::
"$$$$$$ ?$$$$ d$$$$$$$$$$$$$$$P".dP'e$$$$':::::::::::::::
4$$$$$$c $$$$b`$$$$$$$$$$$P"",e$$",$$$$$' ::::::::::::::::
' ?"?$$$b."$$$$.?$$$$$$P".e$$$$F,d$$$$$F ::::::::::::::::::
"?$$bc."$b.$$$$F z$$P?$$",$$$$$$$ ::::::::::::::::::::
`"$$c"?$$$".$$$)e$$F,$$$$$$$' ::::::::::::::::::::
':. "$b...d$$P4$$$",$$$$$$$" :::::::::::::::::::::
':::: "$$$$$".,"".d$$$$$$$F ::::::::::::::::::::::
:::: be."".d$$$4$$$$$$$$F :::::::::::::::::::::::
:::: "??$$$$$$$$$$?$P" :::::::::::::::::::::::::
:::::: ?$$$$$$$$f .::::::::::::::::::::::::::::
:::::::`"????"".::::::::::::::::::::::::::::::