29/03/2012

Behat - jour 4 : API Mink, Sous-contextes et Hooks

Voici l'avant dernier billet de la série sur la prise en main de Behat. Pour rappel, on a vu :

Allons un peu plus loin :-)

Sortir des sentiers battus : l'API de Mink

Assez rapidement on se retrouve à devoir gérer des cas particuliers, par exemple :

Quand je suis à découvert
<p>Alors le bouton "retirer de l'argent" doit être désactivé

On sort des cas classiques de Mink. Comment faire ?

La solution consiste à développer nous même ce comportement :

/**
 * @Then /^le bouton "([^"]*)" doit être désactivé$/
 */
public function leBoutonDoitEtreDesactive($button)
{
    throw new PendingException();
}

On commence par récupérer notre page à partir de l'objet de session:

$page = $this->getSession()->getPage();

Ensuite on va récupérer l'élément html concerné. Il existe différente manière de faire cela. Le plus simple dans notre cas consiste à passer par un des raccourcis de sélection de Mink : findButton(libellé | id | nom)...

$element = $page->findButton($button);

Si l'élément html n'est pas trouvé, on va lever une exception, sinon on va continuer en faisant une assertion simple : l'élément doit avoir l'attribut "disabled". Ce qui donne au final :

$page = $this->getSession()->getPage();
$element = $page->findButton($button);

if (null === $element) {
    throw new Behat\Mink\Exception\ElementNotFoundException(
        $this->getSession(), 'element', 'css', $button
    );
}

<p>assertEquals(true, $element->hasAttribute('disabled'));

Au passage, remarquez qu'il s'agit d'une assertion classique de PHPUnit, mais en mode fonction. Pour cela on aura bien entendu ajouté au début de notre fichier :

require_once 'PHPUnit/Autoload.php';
<p>require_once 'PHPUnit/Framework/Assert/Functions.php';

Je vous laisse regarder la documentation ou la feuille d'astuce pour Mink pour plus d'informations. Sachez juste qu'on peut faire pas mal de chose, comme exécuter du JavaScript par exemple (avec $session->evaluateScript() ) ;-) ...

Organiser son code

Jusqu'ici on a systématiquement mis notre code dans le fichier FeatureContext.php. C'est pas l'idéal : on va très vite se retrouver avec un fichier énorme et imbuvable. Il nous suffit de découper notre contexte en sous-contextes. Tout se fait dans le constructeur du contexte principal :

class FeatureContext extends BehatContext
{

    public function __construct(array $parameters) {
        $this->useContext('mink', new MinkContext($parameters));
        $this->useContext('example1', new MyExample1Context($parameters));
    }

On a donc isolé le contexte de Mink pour en faire un sous-contexte, et on a plus ajouté le nôtre ('example1').

L'utilisation des contextes est assez simple. Chaque sous-contexte a un nom (ici 'mink' et 'behat'), que l'on peut utiliser pour les récupérer :

getMainContext()
Récupérer le contexte principal
getSubContext('nom')
Récupérer un sous contexte
getSubcontexts()
Récupérer la liste des tous les sous-contextes

Par exemple :

$session = $this->getMainContext()->getSubContext('mink')->getSession();

On va donc créer le fichier MyExample1Context.php :

class MyExample1Context extends BehatContext
{

    /**
     * @Then /^le bouton "([^"]*)" doit être désactivé$/
     */
    public function leBoutonDoitEtreDesactive($button) {
        $session = $this->getMainContext()->getSubContext('mink')->getSession();
        $page = $session->getPage();
        $element = $page->findButton($button);

        if (null === $element) {
            throw new Behat\Mink\Exception\ElementNotFoundException(
                    $this->getSession(), 'element', 'css', $button
            );
        }

        assertEquals(true, $element->hasAttribute('disabled'));
    }

}

Et voilà, nous voici avec un code découpé et des fichiers plus spécialisés.

Les hooks de Behat

Comme pour les tests unitaires, il est possible d'exécuter du code à certaines phases du déroulement du tests. Il suffit d'utiliser des annotations :

/**
 * @BeforeSuite
 */
<p>public static function prepare(SuiteEvent $event)</p>
{
    // (...)
}

les déclencheurs disponibles sont :

  • BeforeSuite
  • AfterSuite
  • BeforeFeature
  • AfterFeature
  • BeforeScenario
  • AfterScenario
  • BeforeStep
  • AfterStep
  • AfterStep

Un dessin valant mieux qu'un long discours, le plus simple est de regarder ici.

Conclusion

On voit qu'on a quand même peu de limites avec Mink et Behat. Bien plus, on peut même l'intégrer à une PIC (Jenkins, Hudson...). C'est d'ailleurs ce qu'on verra dans le prochain billet, qui sera le dernier de la série ^^

=> Juste par curiosité : j'utilise exclusivement Sahi pour mes tests. Beaucoup de monde utilise Selenium ? C'est mieux ? Vous avez des avis ?
Pochette du livre Qualité logicielle pour les développeurs

Si ce blog vous plaît, vous trouverez de nombreux conseils pratiques dans mon livre. C'est une bonne manière de me soutenir et de m'encourager

Qualité logicielle pour les développeurs

Le livre qui vous aide à améliorer la qualité de vos projets.

  • ✅ Comment mettre en place des tests automatisés pérennes ;
  • ✅ Comment analyser la qualité de votre code ;
  • ✅ Faites adhérer votre équipe à la qualité logicielle.
blog comments powered by Disqus

© Jean-François Lépine, 2013 - 2024