PHPUnit and Doctrine: How to setup the database - php

I'm trying to write some functional tests for a Symfony2 app.
Those tests interacts with the database, using, obviously, Doctrine.
Now, I setup the configuration to call the test database, but it is empty and has no tables, so my tests fail.
How can I build the database schema into the test database before the execution of the tests?
I have tried this
namespace AppBundle\Tests\Controller;
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
class GetStartedControllerTest extends WebTestCase
{
public function setUp()
{
passthru(sprintf('php "%s/console" cache:clear --env=test --no-warmup --no-interaction', __DIR__));
passthru(sprintf('php "%s/console" doctrine:database:drop --env=test --force --no-interaction', __DIR__));
passthru(sprintf('php "%s/console" doctrine:database:create --env=test --no-interaction', __DIR__));
passthru(sprintf('php "%s/console" doctrine:schema:update --force --env=test --no-interaction', __DIR__));
}
/**
*
*/
public function testRegisterNewUser()
{
...
But it seems not working...
Any ideas? Thank you!

Related

Codeception & Symfony - run Doctrine migrations before tests

I have a Symfony 4 application and Doctrine with Doctrine migrations. I'm introducing Codeception for running API tests, and need to run migrations before the tests run. Since I'm using the Doctrine2 module I don't really want to be also including the DB module as it's not needed for the tests and would require configuring the test database in two different locations.
I am using the Symfony module currently, and I noticed that the Laravel module has a run_database_migrations configuration option.
What is the best way to handle running the Doctrine migrations command in a Symfony app prior to the tests? (bin/console doctrine:migrations:migrate -n is the specific command).
Edit I've got a solution that, although it works, is nowhere near ideal. By using Codeception Customisation I've created the following extension that basically manually execs the underlying Symfony commands.
class DatabaseMigrationExtension extends Extension
{
public static $events = [
Events::SUITE_BEFORE => 'beforeSuite',
];
public function beforeSuite(SuiteEvent $e)
{
echo(exec('bin/console doctrine:database:drop --force') . PHP_EOL);
echo(exec('bin/console doctrine:database:create') . PHP_EOL);
echo(exec('bin/console doctrine:migrations:migrate -n') . PHP_EOL);
}
}
Edit 2 The goal of this is basically to replicate similar functionality to what the Codeception DB module does, which allows you to provide an SQL dump of a database that it automatically uses in the tests, but instead use Doctrine migrations to handle the DB. - https://codeception.com/docs/modules/Db#sql-data-dump
I spent a while trying a couple of different ways to achieve this. I initially used RunProcess however this seemed to cause sporadic issues with the DB being deleted and not recreated, despite using the sleep configuration. I ended up just updating the existing extension to use the CLI module instead, and it works as desired (without having to create scripts or run multiple commands) and without having to use exec.
Final extension;
class DatabaseMigrationExtension extends Extension
{
public static $events = [
Events::SUITE_BEFORE => 'beforeSuite',
];
public function beforeSuite()
{
try {
/** #var \Codeception\Module\Cli $cli */
$cli = $this->getModule('Cli');
$this->writeln('Recreating the DB...');
$cli->runShellCommand('bin/console doctrine:database:drop --if-exists --force');
$cli->seeResultCodeIs(0);
$cli->runShellCommand('bin/console doctrine:database:create');
$cli->seeResultCodeIs(0);
$this->writeln('Running Doctrine Migrations...');
$cli->runShellCommand('bin/console doctrine:migrations:migrate --no-interaction');
$cli->seeResultCodeIs(0);
$this->writeln('Test database recreated');
} catch (\Exception $e) {
$this->writeln(
sprintf(
'An error occurred whilst rebuilding the test database: %s',
$e->getMessage()
)
);
}
}
}
and registered;
// codeception.yml
extensions:
enabled:
- \DatabaseMigrationExtension
Output (-vv or higher also displays the output of the DB & Migration commands);
I always create a bash script to do this, or a Makefile.
bash command
My ./runtests.sh scripts contains
#!/bin/bash
./bin/console command:for:migrations
./bin/phpunit
Makefile
Same with Makefile
.FOO: testsuite
testsuite:
./runtests.sh
or
.FOO: testsuite
testsuite:
./bin/console command:for:migrations
./bin/phpunit
why I prefer Makefile
Recently I added this script in my .bash_profile that allow me to autocomplete from bash all target made in makefile (very easy because you dont need anymore to remember all commands, but just make and tab).
complete -W "`grep -oE '^[a-zA-Z0-9_.-]+:([^=]|$)' Makefile | sed 's/[^a-zA-Z0-9_.-]*$//'`" make
Thus, .. you can create target like:
runtests
runtests_with_fixtures
migrations
runtests_with_migrations
...
and so on
My suggestion is to create your custom and easy way to run commands.
Here a way to run all or just one command usgin make
.FOO: dropforce
dropforce:
bin/console doctrine:database:drop --force
.FOO: dbcreate
dbcreate:
bin/console doctrine:database:create
.FOO: migrate
migrate:
bin/console doctrine:migrations:migrate
.FOO: suite
suite: dropforce dbcreate migrate
With Codeception 4 you can do it without Cli module:
$symfony = $this->getModule('Symfony');
$symfony->runSymfonyConsoleCommand('doctrine:database:drop',['--if-exists'=>true, '--force'=>true]);
$symfony->runSymfonyConsoleCommand('doctrine:database:create');
$symfony->runSymfonyConsoleCommand('doctrine:migrations:migrate', ['--no-interaction'=>true]);

How to load datafixtures hautelook alice in phpunit symfony?

I try to add this code in my DefaultControllerTest
$load = new Loader();
$load->load('src/AppBundle/DataFixtures/ORM/product.yml');
and here is the complete code of my controller
<?php
namespace Tests\AppBundle\Controller;
use Nelmio\Alice\Fixtures\Loader;
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
class DefaultControllerTest extends WebTestCase
{
public function testIndex()
{
$load = new Loader();
$load->load('src/AppBundle/DataFixtures/ORM/product.yml');
$client = static::createClient();
$crawler = $client->request('GET', '/');
$this->assertEquals(200, $client->getResponse()->getStatusCode());
$this->assertContains('Welcome to Symfony', $crawler->filter('#container h1')->text());
}
}
If I run phpunit. It works and no errors found. It successfully tested but the problem here the product.yml doesn't insert any data in my database. But If I run this command bin/console hautelook_alice:doctrine:fixtures:load --append. This will works. It insert the data. How can I load the datafixture before I test the controller? I try to research more about it. but I have no clue on how to add it now.
You can simply use a bash script. Something like this (adapt to your needs):
#!/bin/bash
echo "# Refresh data model and load fixtures"
php bin/console doctrine:database:create --if-not-exists --env=dev
php bin/console doctrine:schema:drop --force --env=dev
php bin/console doctrine:schema:create --env=dev
php bin/console doctrine:schema:validate --env=dev
php bin/console hautelook_alice:doctrine:fixtures:load --append --env=dev
echo -e " --> DONE\n"
Then you can launch phpunit that will use this fresh database. Or you could just add the phpunit call in this script:
./bin/simple-phpunit --debug --verbose

Run specific datafixture + Symfony2

I know you can run all datafixtures by running this command:
php app/console doctrine:fixtures:load
And that you can run a specific fixture by running this command:
php app/console doctrine:fixtures:load --fixtures=/path/to/fixture1
But now I'm trying the second command to load a specific datafixture like this:
php app/console doctrine:fixtures:load --fixtures=/src/VolleyScout/VolleyScoutBundle/DataFixtures/ORM/LoadRegionData
My LoadRegionData class is located at:
src/VolleyScout/VolleyScoutBundle/DataFixtures/ORM/LoadRegionData.php
When I run the command I always get the following error:
[InvalidArgumentException]
Could not find any fixtures to load in:
- /src/VolleyScout/VolleyScoutBundle/DataFixtures/ORM/LoadRegionData
LoadRegionData.php
<?php
namespace VolleyScout\VolleyScoutBundle\DataFixtures\ORM;
use Doctrine\Common\DataFixtures\FixtureInterface;
use Doctrine\Common\Persistence\ObjectManager;
use VolleyScout\VolleyScoutBundle\Entity\Regions;
class LoadRegionData implements FixtureInterface
{
/**
* {#inheritDoc}
*/
public function load(ObjectManager $manager)
{
$regions = ['West-Vlaanderen', 'Oost-Vlaanderen', 'Antwerpen', 'Vlaams-Brabant', 'Limburg', 'Vlaanderen'];
foreach($regions as $r){
$region = new Regions();
$region->setRegionName($r);
$region->setRegionDescription($r);
$manager->persist($region);
$manager->flush();
}
}
}
?>
try
php app/console doctrine:fixtures:load --fixtures=src/VolleyScout/VolleyScoutBundle/DataFixtures/ORM
Try it with the full path:
php app/console doctrine:fixtures:load --fixtures=/Users/foobar/projects/projectname/src/VolleyScout/VolleyScoutBundle/DataFixtures/ORM

Symfony 2 no command for generating doctrine crud

i`m trying to generate CRUD for some entities in Symfony 2, apparently the
generate:doctrine:crud command is unavailable.
[InvalidArgumentException]
Command "generate:doctrine:crud" is not defined.
also , in the list for available commands, I only get one command.
generate
generate:doctrine:entities Generates entity classes and method stubs from your mapping information
is there a bundle or something in the configuration missing, or what is the cause for not having this functionality.
Addition:
The doctrine:generate:crud command is provided by the SensioGeneratorBundle
Please also make sure you have the bundle available and registered in your app/AppKernel.php like this:
class AppKernel extends Kernel
{
public function registerBundles()
{
// ...
);
if (in_array($this->getEnvironment(), array('dev', 'test'))) {
// ...
$bundles[] = new Sensio\Bundle\GeneratorBundle\SensioGeneratorBundle();
// ...
}
As in my example the command is also normally only available in the dev environment. Therefore ...
php app/console --env=prod doctrine:generate:crud
.. or any other configuration that uses production enviroment won't work.
doctrine:generate:crud is the command you should use
You can see a list of commands using php app/console list

Impossible to generate the table "user"

When I install FOSUserBundle (official documentation), I try to generate my table fos_user using this command:
php app/console doctrine:schema:update --force
But console returns the following message
Nothing to update - your database is already in sync with the current entity metadata
I use Symfony 2.1 and the last version to FOSUserBundle.
app/AppKernel.php contains
new FOS\UserBundle\FOSUserBundle(),
app/config/config.yml contains
fos_user:
db_driver: orm # other valid values are 'mongodb', 'couchdb' and 'propel'
firewall_name: main
user_class: Krpano\UserBundle\Entity\User
src/Krpano/UserBundle/Entity/User.php contains
namespace Krpano\UserBundle\Entity;
use FOS\UserBundle\Entity\User as BaseUser;
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\Entity
* #ORM\Table(name="pouet")
*/
class User extends BaseUser
{
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
public function __construct()
{
parent::__construct();
// your own logic
}
}
And when I try to access to my website I have this error:
MappingException: The class 'Krpano\UserBundle\Entity\User' was not found in the chain configured namespaces FOS\UserBundle\Entity, Krpano\ServicesBundle\Entity
Can you help me?
Nothing to update - your database is already in sync with the current entity metadata
Implies that your entity is not registred because of a missing declaration in AppKernel.php.
Doctrine only search on bundle who are active.
After added the line :
new Krpano\UserBundle\KrpanoUserBundle(),
Like that:
public function registerBundles()
{
$bundles = array(
...
new Krpano\UserBundle\KrpanoUserBundle(),
new FOS\UserBundle\FOSUserBundle(),
...
); ...
Try this:
php app/console doctrine:schema:update --force
If Doctrine return:
Database schema updated successfully! "1" queries were executed
Your problem is resolve.
My answer is just a completion to Carlos Granados answer.
Add
new Krpano\UserBundle\KrpanoUserBundle(),
To your app/AppKernel.php file
I had this error and it was caused by having accidentally deleted the #ORM\Entity() line from my entity class. D'oh.
I had the same issue just like you. You missed to create yml for Doctrine Entity. This file is needed for Doctrine to generate shema in your database.
# src/Acme/UserBundle/Resources/config/doctrine/User.orm.yml
Acme\UserBundle\Entity\User:
type: entity
table: fos_user
id:
id:
type: integer
generator:
strategy: AUTO
Then in console update autoload for composer
composer dump-autoload
Then call Doctrine schema builder
php app/console doctrine:schema:update --force
Using composer.phar dump-autoload --optimize
Also provokes this error, when running:
php app/console cache:clear --env=prod --no-debug
If you run:
./composer.phar update
again it all works again.

Categories