Dumping your database on scenario failure in behat

Recently while debugging some tests that were failing on our build server, but passing locally, we needed to see the state of the Database for the application when a test had failed - using Behat hooks and the Symfony Process component, here's how we did it.

This is a quick context that we came up with that will dump a database to a file when a scenario in Behat fails.

The filename will be:

behat-scenario-failed-{scenarioTitle}-{dateStamp}.sql

So if I have a scenario that was run:

Scenario: A user can filter results

The filename would be along the lines of:

behat-scenario-failed-A user can filter results-20170124113226.sql

Notes:

features/bootstrap/App/Context/DbDumpContext.php

<?php

namespace App\Context;

use Behat\Behat\Hook\Scope\AfterScenarioScope;
use Behat\Symfony2Extension\Context\KernelAwareContext;
use Behat\Symfony2Extension\Context\KernelDictionary;
use Symfony\Component\Process\Process;

class DbDumpContext implements KernelAwareContext
{

    use KernelDictionary;

    /**
     * @AfterScenario
     *
     * @param AfterScenarioScope $scope
     */
    public function dumpDatabaseToFile(AfterScenarioScope $scope)
    {
        if ( ! $scope->getTestResult()->isPassed()) {
            $title = $scope->getScenario()->getTitle();
            $processCommand = $this->getProcess($title);

            $sqlDumpProcess = new Process($processCommand);
            $sqlDumpProcess->start();
        }
    }

    /**
     * @param string $scenarioTitle
     *
     * @return string
     */
    private function getDumpFileName($scenarioTitle)
    {
        return sprintf(
            '%s/logs/behat-scenario-failed-%s-%s.sql',
            $this->getKernel()->getRootDir(),
            $scenarioTitle,
            (new \DateTimeImmutable)->format('YmdHis')
        );
    }

    /**
     * @param string $title
     *
     * @return string
     */
    private function getProcess($title)
    {
        $kernel = $this->getKernel();
        $container = $kernel->getContainer();

        return sprintf(
            "mysqldump --user='%s' --password='%s' %s > '%s'",
            $container->getParameter('database_user'),
            $container->getParameter('database_password'),
            $container->getParameter('database_name'),
            $this->getDumpFileName($title)
        );
    }
}

Edit: This has been turned into a little package that we’ll be using across our projects when needed - early stages, but you can find it here: vivait/behat-mysql-dump

Article written by:

Matt

A BDD and TDD fan, his aims and goals are to mentor and help the developers to grow, and to continue making great software.

You might also like...