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:
- This context relies on Symfony and the Behat Symfony 2 Extension as it's pulling parameters from the container and using the kernel. If using another framework, substitute as needed (further improvement would be to pass these in as constructor arguments to the context and configure them in
behat.yml
- homework for you all!) - It also stores the dump in the
app/logs
directory at the minute, this was just because we have the contents of this directory marked as artifacts at the end of a build.
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