Sélectionner une page


PhpSpec est un outil de test basé sur le concept de design prometteur en utilisant la spécification. Vous avez peut-être entendu parler de Behavior Driven Development (BDD), et PhpSpec est un outil qui peut être utilisé au niveau des spécifications ou SpecBDD. Nous avons également mentionné PhpSpec ces derniers temps Résumé des ressources de test LaravelCela inclut les moyens d’intégrer PhpSpec dans votre flux de travail Laravel si vous souhaitez essayer SpecBDD.

Si vous n’avez jamais essayé PhpSpec, l’une des choses que j’aime chez PhpSpec est que le processus génère du code pour vous et vous guide à travers le processus SpecBDD à partir de la ligne de commande. Laissez-moi vous montrer ce que je veux dire avec un court tutoriel.

A débuté

Si vous souhaitez rejoindre, assurez-vous que Composer est installé et dans votre chemin. Nous créons d’abord un nouveau projet. Quand je bricole des bibliothèques, j’aime créer un projet dans un dossier que j’appelle « Sandbox »:

$ mkdir -p ~/Code/sandbox/calculator-phpspec && cd $_
$ mkdir src/

$ composer init
$ composer require --dev phpspec/phpspec

Ensuite, nous ajouterons un espace de noms PSR-4 au fichier composer.json de notre projet. À la fin, votre fichier ressemblera à ceci:

{
    "name": "predmond/calculator-phpspec",
    "require": {},
    "require-dev": {
        "phpspec/phpspec": "^4.0"
    },
    "autoload": {
        "psr-4": {
            "Predmond\Calculator\": "src/"
        }
    }
}

Avant d’oublier, sécurisons l’autoloader afin que notre espace de noms puisse être utilisé plus tard:

$ composer dump-autoload
Generating autoload files

Vous devriez maintenant pouvoir exécuter la CLI phpspec:

# I like to have /vendor/bin in my path
export PATH="./vendor/bin:$PATH"

# Or run it with the path
$ ./vendor/bin/phpspec
phpspec 4.0.3

Usage:
  command [options] [arguments]
...

Configuration de notre suite

PhpSpec recherche un fichier de configuration pour un phpspec.yml Déposer. Nous pouvons utiliser ce fichier pour configurer des suites de tests, des formateurs et d’autres règles de configuration.

Le Documentation de configuration est assez vaste, vous devriez donc le vérifier, mais pour nos besoins, nous voulons simplement configurer notre espace de noms PSR-4 afin que je puisse vous guider à travers le flux de travail d’utilisation de PhpSpec pour extraire une spécification.

PhpSpec utilise une clé YAML de premier niveau appelée « Suites ». Définissez donc une suite par défaut pour l’espace de noms de notre projet en créant un fichier phpspec.yml dans le répertoire racine de notre projet:

suites:
    default:
        namespace: PredmondCalculator
        psr4_prefix: PredmondCalculator
formatter.name: pretty

Avec cette suite, nous pouvons créer une classe de calculatrice et éliminer une spécification de calcul de base. Allons au travail!

Le workflow

Notre flux de travail avec PhpSpec ressemble généralement à ceci:

  1. Décrivez une spécification
  2. Exécutez la spécification (créez la classe si elle n’existe pas).
  3. Ecrire un comportement attendu
  4. Exécutez la spécification (créez la méthode si elle n’existe pas).
  5. Ecrire l’implémentation
  6. Vérifiez le comportement
  7. Répéter

La façon dont PhpSpec fonctionne bien vous oblige à entrer dans ce flux de travail BDD que vous pouvez combattre en premier, mais qui est généralement un flux de travail de codage fiable une fois que vous vous y êtes habitué. Passons en revue un exemple rapide du flux de travail pour que vous puissiez l’essayer!

Description d’une spécification

La première chose à faire est de définir une spécification. Dans notre exemple, nous décrivons une calculatrice de poche. Vous définissez une spécification (imaginez créer une classe de test) en utilisant le describe Commander. Effectuez les étapes suivantes pour créer une spécification de machine:

$ ./vendor/bin/phpspec describe Predmond/Calculator/Calculator

# Or you can use backslashes with quotes
$ ./vendor/bin/phpspec describe "PredmondCalculatorCalculator"

L’exécution de cette commande créera notre fichier de spécification dans spec/CalculatorSpec.php ça ressemble à ça:

<?php

namespace specPredmondCalculator;

use PredmondCalculatorCalculator;
use PhpSpecObjectBehavior;
use ProphecyArgument;

class CalculatorSpec extends ObjectBehavior
{
    function it_is_initializable()
    {
        $this->shouldHaveType(Calculator::class);
    }
}

Remarquerez que Nous n’avons pas encore créé la classe de calculatrice réelle. Notre fichier contient un fichier de spécifications (it_is_initializable) —PhpSpec utilisé it_ et its_ avec des fonctions publiques pour trouver des spécifications.

Gardez également à l’esprit la convention de dénomination de la méthode de soulignement, qui est un style d’opinion qui a tendance à être plus lisible. Un objectif de BDD est d’utiliser un langage convivial pour décrire le comportement.

Maintenant que nous avons notre spécification, utilisons-la run pour réaliser notre cahier des charges:

$ ./vendor/bin/phpspec run
      PredmondCalculatorCalculator

  11  ! is initializable
        class PredmondCalculatorCalculator does not exist.
...
1 specs
1 examples (1 broken)
18ms

Do you want me to create `PredmondCalculatorCalculator` for you? [Y/n]

Entrez « Y » et PhpSpec créera cela Calculator Classer. Exécuter à nouveau les spécifications devrait être le nôtre it_is_initializable Passe de spécification:

$ ./vendor/bin/phpspec run

      PredmondCalculatorCalculator

  11  ✔ is initializable

1 specs
1 examples (1 passed)
9ms

Vous venez de décrire votre première spécification, et PhpSpec s’est occupé des détails de création des méthodes et du code pour nous! Créons plus de spécifications.

Ajout d’une spécification supplémentaire

Imaginons une conception à ajouter dans notre classe de calculatrice. Nos spécifications sont vertes, nous sommes donc prêts à écrire une nouvelle spécification avant de la mettre en œuvre. Ouvrez ça spec/CalculatorSpec.php Fichier et ajoutez ce qui suit:

function it_can_add_two_numbers()
{

}

Je n’ai ajouté aucun code parce que je veux vous montrer comment PhpSpec vous aidera dans les prochaines étapes, ce qui est plutôt chouette:

$ ./vendor/bin/phpspec run

      PredmondCalculatorCalculator

  11  ✔ is initializable
  16  - can add two numbers
        todo: write pending example


1 specs
2 examples (1 passed, 1 pending)
11ms

PhpSpec nous dit qu’une spécification est en attente. Sortons-le maintenant:

function it_can_add_two_numbers()
{
    $this->add(2,3)->shouldReturn(5);
}

Nous utilisons la spécification pour dire: «Appelez add () avec les paramètres 2, et 3, et add () doit retourner 5.

Voici un point important à comprendre: $this est l’objet que nous décrivons. Vous n’êtes pas obligé de créer l’objet comme dans d’autres suites de tests:

# Other test suites
$calculator = new Calculator();

# PhpSpec $this is the Calculator
$this->add(); // And string some matching expectations...

Maintenant, lorsque nous essayons d’exécuter notre spécification, PhpSpec nous indique la prochaine étape:

$ ./vendor/bin/phpspec run

      PredmondCalculatorCalculator

  11  ✔ is initializable
  16  ! can add two numbers
        method PredmondCalculatorCalculator::add not found.

----  broken examples

        Predmond/Calculator/Calculator
  16  ! can add two numbers
        method PredmondCalculatorCalculator::add not found.


1 specs
2 examples (1 passed, 1 broken)
11ms

  Do you want me to create
  `PredmondCalculatorCalculator::add()` for you? [Y/n]

$ ./vendor/bin/phpspec run

      PredmondCalculatorCalculator

  11  ✔ is initializable
  16  ✘ can add two numbers
        expected [integer:5], but got null.

----  failed examples

        Predmond/Calculator/Calculator
  16  ✘ can add two numbers
        expected [integer:5], but got null.


1 specs
2 examples (1 passed, 1 failed)
11ms

PhpSpec définit que add() Méthode pour notre implémentation lorsque nous confirmons « Y ». Un peu cool, non?

Dès que vous confirmez, notre spécification échoue immédiatement. Cela dit, il est temps d’écrire la quantité minimale de code pour qu’il passe la spécification.

Notre Calculator La classe a été générée par PhpSpec à ce moment-là. Ça devrait ressembler à ça:

<?php

namespace PredmondCalculator;

class Calculator
{
    public function add($argument1, $argument2)
    {
        // TODO: write logic here
    }
}

Basé sur notre it_can_add_two_numbers() Spécification, PhpSpec a créé un public add() Méthode avec deux arguments définis. Faisons le montant minimum pour réussir ce test:

public function add($argument1, $argument2)
{
    return 5;
}

La plupart du temps, il est ridicule de faire cette quantité minimale de code, mais restez avec moi car lorsque vous testez des spécifications plus complexes, écrire la quantité minimale de code peut vous aider à créer une spécification robuste.

Après avoir écrit la quantité minimale de code, il est temps d’exécuter à nouveau nos spécifications:

$ ./vendor/bin/phpspec run

      PredmondCalculatorCalculator

  11  ✔ is initializable
  16  ✔ can add two numbers


1 specs
2 examples (2 passed)
20ms

Nous avons une spécification temporaire! Ce n’est pas très utile – mais c’est vert.

Ajoutons quelques exemples supplémentaires à notre spécification pour aider à la mise en œuvre:

function it_can_add_two_numbers()
{
    $this->add(2, 3)->shouldReturn(5);
    $this->add(10, 0)->shouldReturn(10);
    $this->add(0, 0)->shouldReturn(0);
    $this->add(1, -2)->shouldReturn(-1);
}

Si vous exécutez à nouveau vos spécifications, nos spécifications complémentaires échoueront dans un éclat de gloire. Nous sommes prêts à mettre à jour notre implémentation pour rendre les choses à nouveau vertes maintenant:

public function add($argument1, $argument2)
{
    return $argument1 + $argument2;
}

Courir phpspec devrait aboutir à la réussite des deux spécifications.

division

Écrivons rapidement une spécification plus intéressante: Empêcher la division par zéro erreur. Dans ce cas, nous lançons une exception.

La spécification pourrait ressembler à ceci:

function it_can_divide_two_numbers()
{
    $this->divide(10, 2)->shouldReturn(5);
}

function it_throws_a_division_by_zero_excption()
{
    $this->shouldThrow('PredmondCalculatorDivisionByZeroException')->duringDivide(10, 0);
}

Et la mise en œuvre:

public function divide($argument1, $argument2)
{
    return $argument1 / $argument2;
}

Si vous exécutez les spécifications, vous devriez obtenir un avertissement de division par zéro:

$ ./vendor/bin/phpspec run

      PredmondCalculatorCalculator

  11  ✔ is initializable
  16  ✔ can add two numbers
  24  ✔ can divide two numbers
  29  ✘ throws a division by zero exception
        expected exception of class "PredmondCalculatorDivi...", but got
        [exc:PhpSpecExceptionExampleErrorException("warning: Division by zero in
        /Users/predmond/Code/sandbox/calculator-phpspec/src/Calculator.php line 14")].

Corrigeons cela en lançant l’exception lorsque le dénominateur est zéro:

public function divide($numerator, $denominator)
{
    if ($denominator === 0) {
        throw new DivisionByZeroException();
    }

    return $numerator / $denominator;
}

Et assurez-vous de créer la classe d’exception dans le src/ Portefeuille:

<?php

namespace PredmondCalculator;

class DivisionByZeroException extends Exception {}

Et l’exécution de nos spécifications devrait maintenant réussir:

$ ./vendor/bin/phpspec run

      PredmondCalculatorCalculator

  11  ✔ is initializable
  16  ✔ can add two numbers
  24  ✔ can divide two numbers
  29  ✔ throws a division by zero exception


1 specs
4 examples (4 passed)
13ms

Construire des objets et des matchers

Avant de conclure, je voudrais présenter deux concepts importants: la construction d’objets et de matchers.

Notre classe de calculatrice est assez simple, mais vous en aurez probablement besoin Construire des objets qui ont des dépendances. Vous devriez lire ceci Construction d’objets Section pour avoir un aperçu.

Matcher sont utilisés dans PhpSpec pour décrire comment un objet doit se comporter. Tu as déjà utilisé ça Correspondance d’identité quand tu as appelé $this->add(2, 3)->shouldReturn(5);. Le shouldReturn utilise l’opérateur d’identité (===) pour garantir que la spécification est conforme aux attentes. Les quatre types de correspondance d’identité que vous pouvez utiliser sont:

$this->calculatorMemory()->shouldBe(5);
$this->getTitle()->shouldBeEqualTo("Star Wars");
$this->getReleaseDate()->shouldReturn(233366400);
$this->getDescription()->shouldEqual("Inexplicably popular children's film");

Tu as utilisé ça aussi Jeter matcher que nous attendions le nôtre divide() Méthode pour lancer un DivisionByZeroException Exception.

Vous pouvez les consulter documentation complète du matcher et utilisez-le comme référence pour travailler avec PhpSpec.

Apprendre encore plus

Nous venons de gratter la surface des capacités de PhpSpec. Nous n’avons présenté aucun membre du personnel, mais nous pouvons peut-être faire un post de suivi avec plus d’exemples. Vous devriez lire ceci à travers Manuel PhpSpecce qui n’est pas très long. Une fois que vous maîtrisez les choses, vous en saurez plus Objets du prophète Cela inclut les talons, les moqueries et les espions.

j’ai un petit HTML à AMP Bibliothèque qui utilise PhpSpec (et utilise TravisCI). Mike Stowe a un excellent article d’introduction intitulé Qu’est-ce que le développement axé sur les spécifications? Cela vous donnera un aperçu de SpecBDD.



Source link

Recent Posts