
Teilen Sie:
Als ausgebildeter Schauspieler mit einer Dissertation in Standup-Comedy bin ich über die Meetup-Szene zur PHP-Entwicklung gekommen. Man findet mich, wenn ich über Technik spreche oder schreibe, oder wenn ich seltsame Platten aus meiner Vinylsammlung spiele oder kaufe.
Überladen Sie Ihren PHP-Code mit PEST-Mutationstests
PEST hat eine anständige Menge an Akzeptanz erfahren, vor allem seit es die De-facto-Testbibliothek für Laravel Benutzer geworden ist und Laravel-Entwicklern die Möglichkeit gibt, zwischen PHPUnit oder PEST zu wählen, wobei PHPUnit unter der Haube läuft. Mehr Auswahl kann nur eine gute Sache sein, aber die Akzeptanzraten bedeuten auch einen Entwicklungszyklus, in dem viele neue Funktionen ausgeliefert werden.
Die Geschwindigkeit, mit der sich das Mutationstesten durchsetzte, war überraschend, wenn man bedenkt, dass sich in der Welt des Testens nicht viel getan hatte seit Bereichsorientiertes Design und verhaltensgesteuerten Entwicklung. Ich erinnere mich, dass ich bei einer Demonstration von BDD, bei der automatisch geparst wurde, völlig aus dem Häuschen war Gherkin Dateien analysiert und Tests daraus ausspuckt, von Ciaran McNulty auf PHP London vor Jahren. Ich habe das nie professionell gemacht, aber als die Mutationstests von PHP-Entwicklern nach der Popularität von InfectionPHPvon PHP-Entwicklern angenommen wurde, wusste ich, dass es etwas ist, das ich sehr schätzen würde.
Und so werden die Mutationstests immer beliebter, Nuno Maduro angekündigt, dass PEST 3.0 Mutationstests enthalten wird. In diesem Artikel werden wir uns mit einem Beispieltest befassen, der die Vonage Messaging API.
Was sind Mutationstests und warum sollten sie eingesetzt werden?
Lassen Sie mich zunächst sagen, dass alle Tools, die Sie hinzufügen können, um Ihren Code so robust wie möglich zu machen, immer von Vorteil sind. Sie können es also zur Liste der wesentlichen Elemente hinzufügen, wie z. B. die statische Analyse mit Tools wie PsalmPHP oder PHPStan, Linting mit etwas wie phpcsfixerund robuste Tests mit testgetriebener Entwicklung.
Wir sind Menschen, und als solche machen wir in unseren Tests Fehler (ich weiß, dass ich welche gemacht habe). Es gibt viele Möglichkeiten, etwas falsch zu machen - stellen Sie sich vor, Sie sind dabei, einen Test zu schreiben, der keine Assertions enthält, und Sie wollen nur testen, ob der Code ausgeführt wurde, ohne eine Exception auszulösen.
public function testService()
{
$service = new \Vonage\ServiceContainer('dev');
$service->runService();
// If service fails, exception, so dummy completion assertion
$this->assertTrue(true);
}Es handelt sich um ein falsches Positiv. Sicher, Sie können die Gründe dafür erkennen, aber Sie haben auch
100% Line Test CoverageTechnisch korrekt, aber das ist kein echter Test. Was ist, wenn sich der zugrunde liegende Code so ändert, dass die undokumentierte Ausnahme, die möglicherweise ausgelöst wird, nicht mehr auftreten kann?
Bei Mutationstests wird der zugrunde liegende Code geändert, und zwar ein Thread nach dem anderen (wir nennen diese Threads "Mutanten"). Wenn Sie anfangen, den Code zu ändern, sollten eigentlich alle Ihre Tests fehlschlagen. Wir haben bereits das menschliche Element eingeführt, von dem wir wissen, dass dies nicht der Fall sein könnte. Das Endergebnis, nach dem wir suchen, ist, dass viele, viele Mutanten erzeugt wurden, aber alle von ihnen "getötet" wurden, d. h. der Test ist aufgrund der Mutation fehlgeschlagen. Wenn Sie Mutanten haben, die "überleben", sind Ihre Tests noch erfolgreich. Wenn sie immer noch erfolgreich sind, bedeutet das, dass die Tests keine Änderungen in Ihrem Code bemerkt haben. Das ist nicht gut.
Unsere Grundlinie: Vonage PHP SDK Test
Lassen Sie uns zuerst zeigen, wie wir einen regulären Test implementieren, indem wir einen imaginären Laravel-Dienst haben, der eine RCS-Nachricht mit Vonage sendet.
<?php
namespace App\Services;
use Vonage\Client;
use Vonage\Messages\Channel\RCS\RcsText;
class RcsService
{
public function __construct(
private Client $vonage
) {}
public function send(string $to, string $message): array
{
$response = $this->vonage->messages()->send(
new RcsText($to, 'VonageApp', $message)
);
return $response;
}
}Der Einfachheit halber werden wir sagen, dass der Service-Container von Laravel ein vorkonfiguriertes Vonage Client Objekt mit Anmeldeinformationen in den Konstruktor. Jetzt brauchen wir einen Test dafür, der keinen API-Aufruf tätigt. Wir können dies mit Mocks tun.
use App\Services\RcsService;
use Vonage\Client;
use Vonage\Messages\Channel\RCS\RcsText;
use Vonage\Messages\Client as MessagesClient;
beforeEach(function () {
$this->messagesClient = Mockery::mock(MessagesClient::class);
$this->vonage = Mockery::mock(Client::class);
$this->vonage->shouldReceive('messages')->andReturn($this->messagesClient);
});
afterEach(function () {
Mockery::close();
});
test('Will send message using Vonage SDK to end number', function () {
$response = ['message_uuid' => 'abc-123', 'to' => '33600000000'];
$this->messagesClient
->shouldReceive('send')
->once()
->with(Mockery::type(RcsText::class))
->andReturn($response);
$service = new RcsService($this->vonage);
$result = $service->send('+33600000000', 'Hello world');
expect($result)->toBeArray();
});OK, also, der Test wird bestanden. Gut, gut. Was passiert aber, wenn wir den Code ändern?
Die Mutationstests sind in PEST 3 integriert, d. h. wir können die Mutationen sofort ausführen und sehen, was passiert. Es gibt viele Konfigurationsoptionen für PEST, aber der einfachste Weg, Mutationen zu veranlassen, ist die Verwendung der Funktion covers() Hilfsmethode. In diesem Fall wird die folgende Zeile in die Testdatei eingefügt:
use App\Services\RcsService;
covers(RcsService::class);Dadurch wird PEST angewiesen, bei der Ausführung dieser Testdatei den Code in RcsService. So führen Sie PEST-Mutationen mit einem Schwellenwert von 100 % aus:
./vendor/bin/pest --mutate --min=100Wir erhalten das folgende Ergebnis:
Mutating application files...
1 Mutations for 1 Files created
RUN app/Services/RcsService.php
⨯ Line 20: AlwaysReturnEmptyArray
---------------------------------------------------------------------------------------------------------------------------
UNTESTED app/Services/RcsService.php > Line 20: AlwaysReturnEmptyArray - ID: 5befe24d3b8d7f6f
public function send(string $to, string $message): array
{
$response = $this->vonage->messages()->send(new RcsText($to, 'VonageApp', $message));
- return $response;
+ return [];
}
}
Mutations: 1 untested, 0 tested
Score: 0.00%
Duration: 0.30s
FAIL Mutation score below expected: 0.0 %. Minimum: 100.0 %.Oh-oh, irgendetwas stimmt nicht. Aber was? Aha! Sehen Sie die unglaubliche Macht der Mutationstests, die in den folgenden Schritten erklärt werden:
PEST modifiziert die
RcsService()auf immer ein leeres Array zurückgibtPEST führt die Testdatei als Mutante aus
Wir wollen, dass der Mutant scheitert, und somit getötet wird
Tut er nicht, er geht vorbei
Das bedeutet Ihr Test ist zu schwach
Warum also ist sie so schwach? Die Schlussfolgerung ist: Sie sollten die von Vonage zurückgegebene Nutzlast testen. Abgesehen von der Tatsache, dass diese Vonage-API niemals ein leeres Array zurückgibt, sollten Sie die zurückgegebene Nutzlast testen. Mit ->toBeArray() ist in diesem Fall nicht genug.
Ihre Schwäche beheben
Der Test definiert die Scheinausgabe, die gegeben wird, so dass wir davon ausgehen können, dass die zurückgegebene Nutzlast (die wir bereitgestellt haben) in keiner Weise verändert wird. Da wir definiert haben $responsedefiniert haben, sollten wir den Test ändern, um sicherzustellen, dass er genau dieser Datenstruktur entspricht.
expect($result)->toBe($response);Das war's. Eine Zeile, die nur diese Behauptung ändert. Wenn wir die PEST-Mutationen erneut ausführen, erhalten wir folgendes Ergebnis:
Tests: 1 passed (2 assertions)
Duration: 0.26s
Mutating application files...
1 Mutations for 1 Files created
RUN app/Services/RcsService.php
✓ Line 20: AlwaysReturnEmptyArray
Mutations: 1 tested
Score: 100.00%
Duration: 0.34sWow.
Schlussfolgerung
Ich weiß, dass dies ein recht einfaches Beispiel für den Anfang ist. Dennoch ist das Konzept der Mutationstests das, was wir hier hauptsächlich behandeln. Obwohl es sich nur um ein paar Codezeilen handelt, zeigt es, wie mächtig Mutationstests sein können, um Ihre Codebasis abzusichern. Verwenden Sie es zusammen mit PHPStan, und PHP-Entwickler haben es nie besser gehabt, wenn es um die Auslieferung von kampferprobtem Code geht.
Haben Sie eine Frage oder möchten Sie uns mitteilen, was Sie gerade bauen?
Beteiligen Sie sich am Gespräch auf dem Vonage Community Slack
Abonnieren Sie den Entwickler-Newsletter
Folgen Sie uns auf X (früher Twitter) für Updates
Sehen Sie sich die Tutorials auf unserem YouTube-Kanal
Verbinden Sie sich mit uns auf der Vonage Entwickler-Seite auf LinkedIn
Bleiben Sie auf dem Laufenden und halten Sie sich über die neuesten Nachrichten, Tipps und Veranstaltungen für Entwickler auf dem Laufenden.
Teilen Sie:
Als ausgebildeter Schauspieler mit einer Dissertation in Standup-Comedy bin ich über die Meetup-Szene zur PHP-Entwicklung gekommen. Man findet mich, wenn ich über Technik spreche oder schreibe, oder wenn ich seltsame Platten aus meiner Vinylsammlung spiele oder kaufe.