Améliorer Behat pour Drupal avec 3 extensions : screenshot, code coverage, et watchdog

Behat est très puissant pour faire des tests de non regression. Comment le rendre encore plus puissant, avec 3 petites extensions très pratiques pour le debug :

  1. En affichant les warning rajoutés dans le watchdog automatiquement à la fin d’un test. Très pratique pour s’assurer qu’il n’y a pas d’erreur cachées pendant l’exécution des tests
  2. En rajoutant un test de couverture du code avec xdebug et phpcov pour voir si tout est bien testé
  3. En prenant un screenshot automatique de l’étape behat si elle plante, afin de pouvoir voir ou est le problème sans avoir passer par un « Then I break »

Rajouter un display du watchdog à la fin d’un scénario

dans le composer.json de votre répertoire behat (il faut avoir installé composer avant bien sûr)

{
  "require": {
    "drupal/drupal-extension": "~3.0",
    "jorgegc/behat-drupal-extension": "*"
}

dans le shell on fait la mise à jour :

composer update

On rajoute le contexte dans behat.yml

default:
  suites:
    default:
      contexts:
        - JGC\Behat\DrupalExtension\Context\WatchdogContext

Et voila, c’est tout. Il aller chercher un vendor/jorgegc/behat-drupal-extension/src/JGC/Behat/DrupalExtension/Context/WatchdogContext.php qui fait tout le job.

Il suffit de rajouter @watchdog à vos scénarios.

Rajouter un test de couverture de code

dans le composer.json

{
"require": {
"drupal/drupal-extension": "~3.0",
"phpunit/php-code-coverage": "^2.2",
"phpunit/phpcov": "*",
}

Ne pas oublier le « composer update » bien sûr. Et le contexte qui va bien avec features/bootstrap/CoverageContext.php :

use Behat\Behat\Hook\Scope\BeforeScenarioScope;
//require_once('bdd/vendor/phpunit/php-code-coverage/src/CodeCoverage/Filter.php');

/**
 * Created by PhpStorm.
 * User: elie
 * Date: 01/09/15
 * Time: 11:29
 */
class CoverageContext implements Context
{
    /**
     * @var PHP_CodeCoverage
     */
    private static $coverage;

    /** @BeforeSuite */
    public static function setup()
    {
        $filter = new PHP_CodeCoverage_Filter();
        $filter->addDirectoryToBlacklist(__DIR__ . "/../../vendor");
        $filter->addDirectoryToWhitelist(__DIR__ . "/../../src");
        self::$coverage = new PHP_CodeCoverage(null, $filter);
    }

    /** @AfterSuite */
    public static function tearDown()
    {
        $writer = new PHP_CodeCoverage_Report_HTML();
        $writer->process(self::$coverage, __DIR__ . "/../../tmp/coverage");
    }

    private function getCoverageKeyFromScope(BeforeScenarioScope $scope)
    {
        $name = $scope->getFeature()->getTitle() . '::' . $scope->getScenario()->getTitle();
        return $name;
    }

    /**
     * @BeforeScenario
     */
    public function startCoverage(BeforeScenarioScope $scope)
    {
        self::$coverage->start($this->getCoverageKeyFromScope($scope));
    }

    /** @AfterScenario */
    public function stopCoverage()
    {
        self::$coverage->stop();
    }
}

Il faut avoir installé xdebug au préalable. Évidement, en général vos tests behat ne concernent que votre code métier.  phpcov va sûrement vous dire que vous n’avez pas tout testé, et pour cause, vous ne couvrez pas l’ensemble du BO Drupal. Il faudrait donc encore rajouter tous les bons répertoires dans la partie  « addDirectoryToBlacklist ».

Installer xdebug:

sudo apt-get install php5-dev php-pear
sudo pecl install xdebug
find / -name 'xdebug.so' 2> /dev/null

/etc/php5/conf.d/20-xdebug.ini :

zend_extension=/usr/lib/php5/20100525/xdebug.so
xdebug.max_nesting_level=200

La procédure normale n’ayant pas fonctionné dans mon cas (Debian 7).

Screenshot automatique en cas d’erreur

Cette fois ci, c’est un contexte qu’on va rajouter.

Ce n’est pas tout à fait un screenshot qui est fait. Ce n’est pas un .png qui généré, mais une sauvegarde du HTML généré, qu’on peut visualiser dans un navigateur. Et en fait, c’est encore mieux puisque ça nous permet, en plus de voir la page affichée, de voir les éléments HTML.

C’est cette ligne qui fait tout le boulot, le reste ne concerne que l’écriture dans un fichier :

      $html_data = $this->getSession()->getDriver()->getContent();

features/bootstrap/ScreenshotContext.php

<?php

use Drupal\DrupalExtension\Context\RawDrupalContext,
    Drupal\DrupalExtension\Context\DrupalContext;
use Behat\MinkExtension\Context\MinkContext;
use Behat\Behat\Hook\Scope\BeforeScenarioScope,
    Behat\Behat\Hook\Scope\AfterStepScope;

/**
 * Defines application features from the specific context.
 */
class ScreenshotContext extends DrupalContext {

  private $screenshotPath;

  /**
   * Initializes context.
   *
   * Every scenario gets its own context instance.
   * You can also pass arbitrary arguments to the
   * context constructor through behat.yml.
   */
  public function __construct( $tempPath = '/../bdd/tmp', $screenshotPath = '/screenshots', $htmlpagePath = '/behat_page.html' ) {
    $this->tempPath = $tempPath;
    $this->screenshotPath = $screenshotPath;
    $this->htmlPagePath = $htmlpagePath;
  }


 /**
   * Take screen-shot when step fails.
   *
   * @AfterStep
   * @param AfterStepScope $scope
   */
  public function takeScreenshotAfterFailedStep(AfterStepScope $scope)
  {
    // come from : https://github.com/Behat/Behat/issues/649
    // and from : https://gist.github.com/fbrnc/4550079

    global $base_url;

    if (99 === $scope->getTestResult()->getResultCode()) {

      if (! is_dir( $base_url . $this->tempPath . $this->screenshotPath )) {
        mkdir( $base_url . $this->tempPath . $this->screenshotPath, 0777, true );
      }
      $step = $scope->getStep();
            $id = /*$step->getParent()->getTitle() . '.' .*/ $step->getType() . ' ' . $step->getText();
            $id = $scope->getFeature()->getTitle().' '.$step->getLine().'-'.  $step->getType() . ' ' . $step->getText();
            $filename = 'Fail.'.preg_replace('/[^a-zA-Z0-9-_\.]/','_', $id) . '.html';

      $html_data = $this->getSession()->getDriver()->getContent();
      file_put_contents( DRUPAL_ROOT. $this->tempPath . $this->screenshotPath . '/' . $filename, $html_data);
      echo 'Screenshot error at : ' . $base_url . $this->tempPath . $this->screenshotPath . '/' . $filename;
    }
  }
}

Et bien sûr, dans le fichier de conf behat.yml

default:
  suites:
    default:
      contexts:
        - ScreenshotContext

Rejoindre la conversation

1 commentaire

  1. Ping : Cıvata

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *