Advertisement
  1. Code
  2. Web Development

Erste Schritte mit Phpspec

Scroll to top
Read Time: 16 min

() translation by (you can also view the original English article)

In diesem kurzen, aber umfassenden Tutorial betrachten wir die verhaltensgesteuerte Entwicklung (BDD) mit phpspec.  Meistens wird es eine Einführung in das phpspec-Werkzeug geben, aber im weiteren Verlauf werden wir verschiedene BDD-Konzepte ansprechen. BDD ist heutzutage ein heißes Thema und phpspec hat in der PHP-Community in letzter Zeit viel Aufmerksamkeit auf sich gezogen.

SpecBDD & Phpspec

Bei BDD geht es darum, das Verhalten von Software zu beschreiben, um das Design richtig zu machen. Es wird häufig mit TDD in Verbindung gebracht. Während TDD sich jedoch auf das Testen Ihrer Anwendung konzentriert, beschreibt BDD eher dessen Verhalten.  Die Verwendung eines BDD-Ansatzes zwingt Sie dazu, die tatsächlichen Anforderungen und das gewünschte Verhalten der von Ihnen erstellten Software ständig zu berücksichtigen.

In letzter Zeit haben zwei BDD-Tools in der PHP-Community große Beachtung gefunden, Behat und phpspec. Behat hilft Ihnen, das äußere Verhalten Ihrer Anwendung mithilfe der lesbaren Gherkin-Sprache zu beschreiben.  phpspec dagegen hilft Ihnen beim Beschreiben des internen Verhaltens Ihrer Anwendung, indem Sie kleine "specs" in die PHP-Sprache schreiben - daher SpecBDD. Diese Spezifikationen testen, ob Ihr Code das gewünschte Verhalten aufweist.

Was werden wir tun 

In diesem Tutorial erfahren Sie alles über die ersten Schritte mit phpspec. Auf unserem Weg werden wir das Fundament einer ToDo-Listenanwendung Schritt für Schritt mit einem SpecBDD-Ansatz aufbauen. Auf dem Weg dorthin werden wir phpspec den Weg weisen!

Hinweis: Das ist ein Zwischenartikel zu PHP. Ich gehe davon aus, dass Sie objektorientiertes PHP gut verstehen.

Installation

Ich gehe davon aus, dass Sie für dieses Tutorial die folgenden Dinge haben:

  • Ein funktionierendes PHP-Setup (min. 5.3)
  • Composer 

Die Installation von phpspec über Composer ist der einfachste Weg. Sie müssen lediglich den folgenden Befehl in einem Terminal ausführen:

1
$ composer require phpspec/phpspec
2
Please provide a version constraint for the phpspec/phpspec requirement: 2.0.*@dev

Dadurch wird eine composer.json-Datei für Sie erstellt und phpspec in einem vendor/-Verzeichnis installiert.

Um sicherzustellen, dass alles funktioniert, führen Sie phpspec aus und stellen Sie sicher, dass Sie die folgende Ausgabe erhalten:

1
$ vendor/bin/phpspec run
2
3
0 specs
4
0 examples 
5
0ms

Aufbau

Bevor wir beginnen, müssen wir ein wenig Konfiguration vornehmen. Bei der Ausführung von phpspec wird nach einer YAML-Datei mit dem Namen phpspec.yml gesucht.  Da wir unseren Code in einen Namespace einfügen, müssen wir sicherstellen, dass phpspec dies weiß. Wenn wir dabei sind, stellen wir sicher, dass unsere Spezifikationen schön aussehen, wenn wir sie ausführen.

Machen Sie die Datei mit folgendem Inhalt:

1
formatter.name: pretty
2
suites:
3
    todo_suite:
4
        namespace: Petersuhm\Todo

Es gibt viele weitere Konfigurationsoptionen, die Sie in der Dokumentation nachlesen können.

Eine weitere Sache, die wir tun müssen, ist Composer mitzuteilen, wie er unseren Code automatisch lädt. phpspec verwendet den Autoloader von Composer. Das ist für die Ausführung unserer Spezifikationen erforderlich.

Fügen Sie der composer.json-Datei, die Composer für Sie erstellt hat, ein Autoload-Element hinzu:

1
{
2
    "require": {
3
        "phpspec/phpspec": "2.0.*@dev"
4
    },
5
    "autoload": {
6
        "psr-0": {
7
            "Petersuhm\\Todo": "src"
8
        }
9
    }
10
}

Wenn Sie composer dump-autoload ausführen, wird der Autoloader nach dieser Änderung aktualisiert.

Unsere erste Spec

Nun können wir unsere erste Spezifikation schreiben. Wir beginnen mit der Beschreibung einer Klasse namens TaskCollection. Phpspec generiert eine Spezifikationsklasse für uns, indem Sie den describe-Befehl (oder alternativ die Kurzversion desc) verwenden.

1
$ vendor/bin/phpspec describe "Petersuhm\Todo\TaskCollection"
2
$ vendor/bin/phpspec run
3
Do you want me to create `Petersuhm\Todo\TaskCollection` for you? y

Was ist also hier passiert? Zuerst haben wir phpspec gebeten, eine Spezifikation für eine TaskCollection zu erstellen. Zweitens ließen wir unsere Spec Suite laufen, und dann bot phpspec automatisch an, die eigentliche TaskCollection-Klasse für uns zu erstellen. Cool, nicht wahr?

Fahren Sie fort und führen Sie die Suite erneut aus. Sie werden sehen, dass wir bereits ein Beispiel in unserer Spezifikation haben (wir werden gleich sehen, was ein Beispiel ist):

1
$ vendor/bin/phpspec run
2
3
      Petersuhm\Todo\TaskCollection
4
5
  10  ✔ is initializable
6
7
8
1 specs
9
1 examples (1 passed)
10
7ms

In dieser Ausgabe sehen wir, dass die TaskCollection initialisierbar ist. Um was geht es hierbei? Schauen Sie sich die von phpspec generierte spec-Datei an, und es sollte klarer sein:

1
<?php
2
3
namespace spec\Petersuhm\Todo;
4
5
use PhpSpec\ObjectBehavior;
6
use Prophecy\Argument;
7
8
class TaskCollectionSpec extends ObjectBehavior
9
{
10
    function it_is_initializable()
11
    {
12
        $this->shouldHaveType('Petersuhm\Todo\TaskCollection');
13
    }
14
}

Der Ausdruck 'ist initialisierbar' stammt von einer Funktion namens it_is_initializable(), die phpspec einer Klasse mit dem Namen TaskCollectionSpec hinzugefügt hat.  Auf diese Funktion beziehen wir uns als Beispiel. In diesem speziellen Beispiel haben wir das, was wir als Matcher bezeichnen, sollte shouldHaveType() genannt werden, der den Typ unserer TaskCollection überprüft.  Wenn Sie den an diese Funktion übergebenen Parameter in etwas anderes ändern und die Spezifikation erneut ausführen, werden Sie feststellen, dass sie fehlschlägt. Bevor wir das vollständig verstehen, müssen wir zunächst untersuchen, worauf sich die $this-Variable bezieht, auf die sich das in unserer Spec bezieht.

Was ist $this?

$this bezieht sich natürlich auf die Instanz der Klasse TaskCollectionSpec, da es sich nur um normalen PHP-Code handelt.  Aber mit phpspec müssen Sie $this anders behandeln, als Sie es normalerweise tun, denn unter der Haube bezieht sich dies tatsächlich auf das zu testende Objekt, das ist die TaskCollection-Klasse.  Dieses Verhalten wird von der Klasse ObjectBehavior geerbt. Dadurch wird sichergestellt, dass Funktionsaufrufe an die angegebene Klasse weitergeleitet werden.  Das bedeutet, dass SomeClassSpec Methodenaufrufe an eine Instanz von SomeClass durchführen wird. phpspec bindet diese Methodenaufrufe um, um ihre Rückgabewerte gegen Matcher wie den gerade gesehenen auszuführen.

Sie benötigen kein tiefes Verständnis dafür, um phpspec verwenden zu können. Denken Sie jedoch daran, dass $this sich auf das zu testende Objekt bezieht.

Aufbau unserer Aufgabensammlung 

Bisher haben wir selbst nichts unternommen. Phpspec hat jedoch eine leere TaskCollection-Klasse für uns erstellt. Jetzt ist es an der Zeit, etwas Code einzufügen und diese Klasse nützlich zu machen.  Wir fügen zwei Methoden hinzu: eine add()-Methode zum Hinzufügen von Aufgaben und eine count()-Methode zum Zählen der Anzahl der Aufgaben in der Auflistung.

Aufgabe hinzufügen 

Bevor wir echten Code schreiben, sollten wir ein Beispiel in unsere Spezifikation schreiben. In unserem Beispiel möchten wir versuchen, der Auflistung eine Aufgabe hinzuzufügen, und danach sicherstellen, dass die Aufgabe tatsächlich hinzugefügt wird.  Dazu benötigen wir eine Instanz der (bisher nicht vorhandenen) Task-Klasse. Wenn wir diese Abhängigkeit als Parameter zu unserer Spezifikationsfunktion hinzufügen, gibt uns phpspec automatisch eine Instanz, die wir verwenden können.  Tatsächlich ist die Instanz keine echte Instanz, sondern das, worauf sich phpspec als Collaborator bezieht. Dieses Objekt wird als echtes Objekt fungieren, aber mit phpspec können wir noch mehr ausgefallenere Sachen machen, die wir bald sehen werden.  Auch wenn die Task-Klasse noch nicht existiert, tun Sie einfach so, als ob sie es tut. Öffnen Sie die TaskCollectionSpec und fügen Sie eine use-Anweisung für die Task-Klasse hinzu. Fügen Sie dann das Beispiel it_adds_a_task_to_the_collection() hinzu:

1
use Petersuhm\Todo\Task;
2
3
...
4
5
function it_adds_a_task_to_the_collection(Task $task)
6
{
7
    $this->add($task);
8
    $this->tasks[0]->shouldBe($task);
9
}

In unserem Beispiel schreiben wir den Code "Wir wünschten, wir hätten". Wir rufen die add()-Methode auf und versuchen dann, ihr eine $task zu geben. Dann prüfen wir, ob die Task tatsächlich zu der Instanzvariablen $tasks hinzugefügt wurde.  Der Matcher shouldBe() ist ein Identitätsmatcher, der dem Vergleicher PHP === ähnelt. Sie können entweder shouldBe(), shouldBeEqualTo(), shouldEqual() oder shouldReturn() verwenden - sie alle tun dasselbe.

Das Ausführen von phpspec führt zu einigen Fehlern, da wir noch keine Klasse namens Task haben.

Lassen Sie uns phpspec das für uns beheben:

1
$ vendor/bin/phpspec describe "Petersuhm\Todo\Task"
2
$ vendor/bin/phpspec run
3
Do you want me to create `Petersuhm\Todo\Task` for you? y

Wenn Sie phpspec erneut ausführen, passiert etwas Interessantes:

1
$ vendor/bin/phpspec run
2
Do you want me to create `Petersuhm\Todo\TaskCollection::add()` for you? y

Perfekt! Wenn Sie sich die TaskCollection.php-Datei ansehen, werden Sie feststellen, dass phpspec eine add() - Funktion erstellt hat, die wir ausfüllen sollten:

1
<?php
2
3
namespace Petersuhm\Todo;
4
5
class TaskCollection
6
{
7
8
    public function add($argument1)
9
    {
10
        // TODO: write logic here

11
    }
12
}

phpspec beschwert sich jedoch immer noch. Wir haben kein $task-Array, also erstellen wir eines und fügen die Aufgabe hinzu:

1
<?php
2
3
namespace Petersuhm\Todo;
4
5
class TaskCollection
6
{
7
    public $tasks;
8
9
    public function add(Task $task)
10
    {
11
        $this->tasks[] = $task;
12
    }
13
}

Jetzt sind unsere Angaben alle schön grün. Beachten Sie, dass ich den $task-Parameter eingetippt habe.

Um sicherzugehen, dass wir alles richtig gemacht haben, fügen wir eine weitere Aufgabe hinzu:

1
function it_adds_a_task_to_the_collection(Task $task, Task $anotherTask)
2
{
3
    $this->add($task);
4
    $this->tasks[0]->shouldBe($task);
5
6
    $this->add($anotherTask);
7
    $this->tasks[1]->shouldBe($anotherTask);
8
}

Phpspec läuft, es sieht so aus, als ob wir alle gut sind.

Implementierung der Countable-Schnittstelle

Wir möchten wissen, wie viele Aufgaben sich in einer Sammlung befinden. Dies ist ein guter Grund, eine der Schnittstellen der Standard PHP Library (SPL) zu verwenden, nämlich die Countable-Schnittstelle. Diese Schnittstelle schreibt vor, dass eine Klasse, die sie implementiert, eine count()-Methode haben muss.

Früher haben wir den Matcher shouldHaveType() verwendet, der ein Typ Matcher ist. Sie verwendet die PHP-Vergleicher-instanceof, um zu überprüfen, ob ein Objekt tatsächlich eine Instanz einer bestimmten Klasse ist.  Es gibt 4 Matcher, die alle dasselbe tun. Eines von ihnen ist shouldImplement(), das perfekt für unsere Zwecke ist. Lassen Sie uns das also in einem Beispiel ausführen:

1
function it_is_countable()
2
{
3
    $this->shouldImplement('Countable');
4
}

Sehen Sie, wie schön das liest? Lassen Sie uns das Beispiel ausführen und phpspec uns den Weg weisen:

1
$ vendor/bin/phpspec run
2
3
        Petersuhm/Todo/TaskCollection
4
  25  ✘ is countable
5
        expected an instance of Countable, but got [obj:Petersuhm\Todo\TaskCollection].

Okay, unsere Klasse ist keine Instanz von Countable, da wir sie noch nicht implementiert haben. Lassen Sie uns den Code für unsere TaskCollection-Klasse aktualisieren:

1
class TaskCollection implements \Countable

Unsere Tests werden nicht ausgeführt, da die Countable-Schnittstelle die abstrakte Methode count() hat, die wir implementieren müssen. Eine leere Methode macht den Trick fürs Erste:

1
public function count()
2
{
3
    // ...

4
}

Und wir sind wieder grün. Im Moment macht unsere Methode count() nicht viel und ist eigentlich ziemlich nutzlos. Schreiben wir eine Spezifikation für das Verhalten, das wir wünschen. Erstens wird erwartet, dass unsere Zählfunktion ohne Aufgaben null zurückgibt:

1
function it_counts_elements_of_the_collection()
2
{
3
    $this->count()->shouldReturn(0);
4
}

Es gibt null statt 0 zurück. Um einen grünen Test zu erhalten, lassen Sie uns dies auf TDD/BDD-Weise korrigieren:

1
public function count()
2
{
3
    return 0;
4
}

Wir sind grün und alles ist gut, aber das ist wahrscheinlich nicht das Verhalten, das wir wollen. Lassen Sie uns stattdessen unsere Spezifikation erweitern und etwas zum $task-Array hinzufügen:

1
function it_counts_elements_of_the_collection()
2
{
3
    $this->count()->shouldReturn(0);
4
5
    $this->tasks = ['foo'];
6
    $this->count()->shouldReturn(1);
7
}

Natürlich gibt unser Code immer noch 0 zurück und wir haben einen roten Schritt. Das Problem zu beheben ist nicht allzu schwierig und unsere TaskCollection-Klasse sollte jetzt so aussehen:

1
<?php
2
3
namespace Petersuhm\Todo;
4
5
class TaskCollection implements \Countable
6
{
7
    public $tasks;
8
9
    public function add(Task $task)
10
    {
11
        $this->tasks[] = $task;
12
    }
13
14
    public function count()
15
    {
16
        return count($this->tasks);
17
    }
18
}

Wir haben einen grünen Test und unsere count()-Methode funktioniert. Was für ein Tag!

Erwartungen & Versprechen

Erinnern Sie sich, ich habe Ihnen gesagt, dass Sie mit phpspec coole Sachen mit Instanzen der Collaborator-Klasse machen können, auch wenn die Instanzen automatisch von phpspec eingefügt werden?  Wenn Sie bereits Unit-Tests geschrieben haben, wissen Sie, was Mocks und Stubs sind. Wenn Sie dies nicht tun, machen Sie sich bitte nicht zu viele Sorgen. Es ist nur Jargon.  Diese Dinge beziehen sich auf "gefälschte" Objekte, die als Ihre realen Objekte fungieren, aber Sie können sie isoliert testen. phpspec wandelt diese Collaborator-Instanzen automatisch in Mocks und Stubs um, wenn Sie es in Ihren Spezifikationen benötigen.

Das ist wirklich großartig. Unter der Haube verwendet phpspec die Prophecy-Bibliothek, die ein hochmeinendes Spott-Framework ist, das gut mit phpspec spielt (und von den gleichen fantastischen Leuten gebaut wird).  Sie können eine Erwartung für einen Collaborator festlegen (Mocking), wie "Diese Methode sollte aufgerufen werden", und Sie können Versprechen (Stubbing) hinzufügen, wie "Diese Methode gibt diesen Wert zurück". Mit phpspec ist das wirklich einfach und wir werden als Nächstes beides tun.

Lassen Sie uns eine Klasse erstellen, die wir TodoList nennen, die unsere Collection-Klasse verwenden kann.

1
$ vendor/bin/phpspec desc "Petersuhm\Todo\TodoList"
2
$ vendor/bin/phpspec run
3
Do you want me to create `Petersuhm\Todo\TodoList` for you? y

Aufgaben hinzufügen

Das erste Beispiel, das wir hinzufügen, ist das Hinzufügen von Aufgaben. Wir erstellen eine addTask()-Methode, die nichts weiter tut, als unserer Sammlung eine Aufgabe hinzuzufügen.  Es leitet den Aufruf einfach an die add()-Methode der Collection weiter, so dass dies der perfekte Ort ist, um die Erwartung zu nutzen.  Wir möchten nicht, dass die Methode die add()-Methode tatsächlich aufruft, wir möchten nur sicherstellen, dass sie versucht, das zu tun. Außerdem möchten wir sicherstellen, dass es nur einmal aufgerufen wird. Sehen Sie sich an, wie wir mit phpspec vorgehen können:

1
<?php
2
3
namespace spec\Petersuhm\Todo;
4
5
use PhpSpec\ObjectBehavior;
6
use Prophecy\Argument;
7
use Petersuhm\Todo\TaskCollection;
8
use Petersuhm\Todo\Task;
9
10
class TodoListSpec extends ObjectBehavior
11
{
12
    function it_is_initializable()
13
    {
14
        $this->shouldHaveType('Petersuhm\Todo\TodoList');
15
    }
16
17
    function it_adds_a_task_to_the_list(TaskCollection $tasks, Task $task)
18
    {
19
        $tasks->add($task)->shouldBeCalledTimes(1);
20
        $this->tasks = $tasks;
21
22
        $this->addTask($task);
23
    }
24
}

Erstens haben wir mit phpspec die zwei Mitarbeiter, die wir brauchen: eine Auflistung von Aufgaben und eine Aufgabe.  Dann setzen wir eine Erwartung für den Task Collection Collaborator, die im Wesentlichen besagt: "Die add()-Methode sollte genau 1 Mal mit der Variablen $task als Parameter aufgerufen werden".  So bereiten wir unseren Mitarbeiter vor, der jetzt ein Mock ist, bevor wir ihn der $task-Eigenschaft in der TodoList zuweisen. Schließlich versuchen wir, die addTask()-Methode tatsächlich aufzurufen.

Ok, was hat phpspec dazu zu sagen:

1
$ vendor/bin/phpspec run
2
3
        Petersuhm/Todo/TodoList
4
  17  ! adds a task to the list
5
        property tasks not found.

Die $task-Eigenschaft ist nicht vorhanden - einfach:

1
<?php
2
3
namespace Petersuhm\Todo;
4
5
class TodoList
6
{
7
    public $tasks;
8
}

Versuchen Sie es erneut und lassen Sie sich von phpspec leiten:

1
$ vendor/bin/phpspec run
2
Do you want me to create `Petersuhm\Todo\TodoList::addTask()` for you? y
3
$ vendor/bin/phpspec run
4
5
        Petersuhm/Todo/TodoList
6
  17  ✘ adds a task to the list
7
        some predictions failed:
8
          Double\Petersuhm\Todo\TaskCollection\P4:
9
            Expected exactly 1 calls that match:
10
              Double\Petersuhm\Todo\TaskCollection\P4->add(exact(Double\Petersuhm\Todo\Task\P3:000000002544d76d0000000059fcae53))
11
            but none were made.

Okay, jetzt ist etwas Interessantes passiert. Siehe die Meldung "Erwartet genau 1 passende Anrufe: ..."? Das ist unsere versagte Erwartung.  Das geschieht, weil nach dem Aufrufen der addTask()-Methode die add()-Methode für die Auflistung nicht aufgerufen wurde, was wir erwartet hatten.

Um wieder grün zu werden, geben Sie den folgenden Code in die leere addTask()-Methode ein:

1
<?php
2
3
namespace Petersuhm\Todo;
4
5
class TodoList
6
{
7
    public $tasks;
8
9
    public function addTask(Task $task)
10
    {
11
        $this->tasks->add($task);
12
    }
13
}

Zurück zu grün! Es fühlt sich gut an, richtig?

Überprüfung der Aufgaben

Schauen wir uns auch die Versprechen an. Wir möchten eine Methode, die uns sagen kann, ob Aufgaben in der Sammlung vorhanden sind. Dazu prüfen wir einfach den Rückgabewert der count()-Methode für die Auflistung.  Wieder benötigen wir keine echte Instanz mit einer echten count()-Methode. Wir müssen nur sicherstellen, dass unser Code eine count()-Methode aufruft, und abhängig vom Rückgabewert einige Dinge tun.

Schauen Sie sich das folgende Beispiel an:

1
function it_checks_whether_it_has_any_tasks(TaskCollection $tasks)
2
{
3
    $tasks->count()->willReturn(0);
4
    $this->tasks = $tasks;
5
6
    $this->hasTasks()->shouldReturn(false);
7
}

Wir haben einen Task Collection Collaborator, der eine count()-Methode hat, die Null zurückgibt. Das ist unser Versprechen. Das bedeutet, dass bei jedem Aufruf der count()-Methode Null zurückgegeben wird.  Dann weisen wir den vorbereiteten Mitarbeiter der $task-Eigenschaft in unserem Objekt zu. Schließlich versuchen wir, eine Methode hasTasks() aufzurufen, und stellen sicher, dass sie false zurückgibt.

Was hat phspec dazu zu sagen?

1
$ vendor/bin/phpspec run
2
Do you want me to create `Petersuhm\Todo\TodoList::hasTasks()` for you? y
3
$ vendor/bin/phpspec run
4
5
        Petersuhm/Todo/TodoList
6
  25  ✘ checks whether it has any tasks
7
        expected false, but got null.

Cool. phpspec hat uns zu einer hasTasks()-Methode gemacht, und es ist nicht überraschend, dass sie null und nicht false zurückgibt.

Wieder ist das leicht zu beheben:

1
public function hasTasks()
2
{
3
    return false;
4
}

Wir sind wieder grün, aber das wollen wir nicht. Lassen Sie uns auf Aufgaben prüfen, wenn es 20 davon gibt. Das sollte true zurückgeben:

1
function it_checks_whether_it_has_any_tasks(TaskCollection $tasks)
2
{
3
    $tasks->count()->willReturn(0);
4
    $this->tasks = $tasks;
5
6
    $this->hasTasks()->shouldReturn(false);
7
8
    $tasks->count()->willReturn(20);
9
    $this->tasks = $tasks;
10
11
    $this->hasTasks()->shouldReturn(true);
12
}

Führen Sie phspec aus und wir erhalten:

1
$ vendor/bin/phpspec run
2
3
        Petersuhm/Todo/TodoList
4
  25  ✘ checks whether it has any tasks
5
        expected true, but got false.

Okay, false ist nicht true, also müssen wir unseren Code verbessern. Verwenden Sie diese count()-Methode, um zu sehen, ob es Aufgaben gibt oder nicht:

1
public function hasTasks()
2
{
3
    if ($this->tasks->count() > 0)
4
        return true;
5
6
    return false;
7
}

Tah dah! Zurück zu grün!

Benutzerdefinierte Matcher erstellen

Zum Schreiben guter Spezifikationen gehört es, sie so lesbar wie möglich zu machen. Unser letztes Beispiel kann dank der angepassten Matcher von phpspec sogar ein bisschen verbessert werden.  Es ist einfach, benutzerdefinierte Matcher zu implementieren - wir müssen nur die getMatchers()-Methode überschreiben, die von ObjectBehavior geerbt wird. Durch die Implementierung von zwei benutzerdefinierten Matchern können unsere Spezifikationen folgendermaßen geändert werden:

1
function it_checks_whether_it_has_any_tasks(TaskCollection $tasks)
2
{
3
    $tasks->count()->willReturn(0);
4
    $this->tasks = $tasks;
5
6
    $this->hasTasks()->shouldBeFalse();
7
8
    $tasks->count()->willReturn(20);
9
    $this->tasks = $tasks;
10
11
    $this->hasTasks()->shouldBeTrue();
12
}
13
14
function getMatchers()
15
{
16
    return [
17
        'beTrue' => function($subject) {
18
            return $subject === true;
19
        },
20
        'beFalse' => function($subject) {
21
            return $subject === false;
22
        },
23
    ];
24
}

Ich finde das sieht ziemlich gut aus. Denken Sie daran, dass das Umgestalten Ihrer Daten wichtig ist, um sie auf dem neuesten Stand zu halten. Durch die Implementierung eigener Matcher können Sie Ihre Daten bereinigen und sie lesbarer machen.

Eigentlich können wir auch die Negation der Matcher verwenden:

1
function it_checks_whether_it_has_any_tasks(TaskCollection $tasks)
2
{
3
    $tasks->count()->willReturn(0);
4
    $this->tasks = $tasks;
5
6
    $this->hasTasks()->shouldNotBeTrue();
7
8
    $tasks->count()->willReturn(20);
9
    $this->tasks = $tasks;
10
11
    $this->hasTasks()->shouldNotBeFalse();
12
}

Ja. Ziemlich cool!

Schlussfolgerung

Alle unsere Angaben sind grün und schauen Sie sich an, wie schön sie unseren Code dokumentieren!

1
      Petersuhm\Todo\TaskCollection
2
3
  10  ✔ is initializable
4
  15  ✔ adds a task to the collection
5
  24  ✔ is countable
6
  29  ✔ counts elements of the collection
7
8
      Petersuhm\Todo\Task
9
10
  10  ✔ is initializable
11
12
      Petersuhm\Todo\TodoList
13
14
  11  ✔ is initializable
15
  16  ✔ adds a task to the list
16
  24  ✔ checks whether it has any tasks
17
18
19
3 specs
20
8 examples (8 passed)
21
16ms

Wir haben das gewünschte Verhalten unseres Codes effektiv beschrieben und erreicht. Nicht zu vergessen, unser Code wird zu 100% von unseren Spezifikationen abgedeckt, was bedeutet, dass das Refactoring keine angstauslösende Erfahrung sein wird.

Ich hoffe, dass Sie inspiriert wurden, phpspec auszuprobieren. Es ist mehr als ein Testwerkzeug - es ist ein Entwurfswerkzeug. Wenn Sie sich erst einmal mit phpspec (und seinen fantastischen Code-Generierungswerkzeugen) vertraut gemacht haben, fällt es Ihnen schwer, es wieder loszulassen!  Die Leute beschweren sich oft, dass TDD oder BDD sie verlangsamt. Nachdem ich phpspec in meinen Arbeitsablauf aufgenommen habe, fühle ich das Gegenteil - meine Produktivität ist deutlich verbessert. Und mein Code ist solider!

Advertisement
Did you find this post useful?
Want a weekly email summary?
Subscribe below and we’ll send you a weekly email summary of all new Code tutorials. Never miss out on learning about the next big thing.
Advertisement
Looking for something to help kick start your next project?
Envato Market has a range of items for sale to help get you started.