Load fixtures one time before all phpunit test on symfony 3 - performance

I ve got a SF3 application and lot of functionnals tests.
Before each tests we load and purge all fixtures.
Time of all tests are so long.
I would like to load fixtures just one time et truncate after last test.
Is it the good method to improve functionnal tests speed ?
Is there a php method in phpunit which is launched just one time before all tests ? (Because setUpBeforeClass is executed before each test)
An exemple of the setUpBeforeClass method in my test's classes.
class SearchRegisterControllerTest extends WebTestCase
{
/** #var Client $client */
private $client;
protected static $application;
public static function setUpBeforeClass()
{
$kernel = static::createKernel();
$kernel->boot();
$em = $kernel->getContainer()->get('doctrine.orm.entity_manager');
$schemaTool = new SchemaTool($em);
$metadata = $em->getMetadataFactory()->getAllMetadata();
$schemaTool->dropSchema($metadata);
$schemaTool->createSchema($metadata);
/** #var Client $client */
$client = static::createClient();
$em = $client->getContainer()->get('doctrine.orm.entity_manager');
$loader = new Loader();
$loader->loadFromDirectory('src/MyNameSpace/AppBundle/DataFixtures/ORM');
$purger = new ORMPurger();
$executor = new ORMExecutor($em, $purger);
$executor->execute($loader->getFixtures(), true);
}
Thanks in advance.

You could implement a test listener.
tests/StartTestSuiteListener.php
namespace App\Tests;
class StartTestSuite extends \PHPUnit_Framework_BaseTestListener
{
public function startTestSuite(\PHPUnit_Framework_TestSuite $suite)
{
// do initial stuff
}
}
Then enable enable the test listener in your phpunit.xml config:
phpunit.xml
<phpunit
...
>
<listeners>
<listener class="App\Tests\StartTestSuiteListener">
</listener>
</listeners>
[...]
</phpunit>
In the same manner you could implement a endTestSuite (Check for all event listed in the doc)
Hope this help

You can use bash script like this to load fixtures once before all tests.
php bin/console doctrine:database:create --env=test --if-not-exists
php bin/console doctrine:schema:update --force --env=test --complete
php bin/console doctrine:fixtures:load --fixtures=tests/fixtures/api --env=test --no-interaction
php vendor/bin/phpunit tests/Functional
Keep in mind that your test will not be executed within isolated environments with fresh data and thus will interfere with each other.

Related

Laravel Undefined property in job

In a Laravel job I have:
use Spatie\Valuestore\Valuestore;
and
public function __construct()
{
$this->settings = Valuestore::make(storage_path('app/settings.json'));
}
and
public function handle()
{
if($this->settings->get('foo') == 'test') {
etc...
and on this I get an error Undefined property App\Jobs\MyJobName::$settings. What is going wrong?
Even if I do this:
public function handle()
{
$this->settings = Valuestore::make(storage_path('app/settings.json'));
if($this->settings->get('foo') == 'test') {
etc...
I get the same error.
Update based on the comments
MyJobName is called in a custom artisan command, that happens to also use Valuestore but I assume that would unrelated.
In the class CustomCommand:
use Spatie\Valuestore\Valuestore;
and
public function __construct()
{
parent::__construct();
$this->settings = Valuestore::make(storage_path('app/settings.json'));
}
and
public function handle()
{
if($this->settings->get('foo') == 'test') // This works in this custom command!
{
$controller = new MyController;
MyJobName::dispatch($controller);
}
}
So in CustomCommand I use Valuestore in exactly the same way as in MyJobName but in the latter it doesn't work.
As per one of the comments: I do not make $this->settings global as I don't do that in CustomCommand either and it works fine there.
Update 2
If I add protected $settings; above the __construct() function as per the comments it still doesn't work, same error.
Just declare the settings property as public in your Job Class.
public $settings;
public function __construct()
{
$this->settings = Valuestore::make(storage_path('app/settings.json'));
}
I recently had this error. I've tried to make the variables public, delete all the variable inside the Jobs class and even rename and delete the class itself. But it didn't work.
Shortly, I run this artisan command php artisan optimize:clear to clear all the caches, views, routes, etc. And it somehow solve the problem about variable in my problem. For anyone who is still have this OP's problem, give a try to my solution above.
If you use JOB by QUEUE, you need all the requests or SQL queries to do by the method handle
public function handle()
{
$this->settings = Valuestore::make(storage_path('app/settings.json'));
....
}
Because the constructor works when you make the object of class, and this object is serialized and stored in the database and after the unserialization and the handle is triggered.
You may need to restart your queue worker
From Laravel documentation
Remember, queue workers are long-lived processes and store the booted application state in memory. As a result, they will not notice changes in your code base after they have been started. So, during your deployment process, be sure to restart your queue workers.
If you use a daemon php artisan queue:restart
If you use queue:work on your bash hit Ctrl+C then again php artisan queue:work should be enough

Symfony 4.1 KernelTestCase Repository ConnectionException

I'm following the symfony docs (https://symfony.com/doc/current/testing/doctrine.html) trying to test my repository classes against my MySQL database.
The relevant code part is this:
class ProductRepositoryTest extends KernelTestCase
{
/**
* #var \Doctrine\ORM\EntityManager
*/
private $entityManager;
/**
* {#inheritDoc}
*/
protected function setUp()
{
$kernel = self::bootKernel();
$this->entityManager = $kernel->getContainer()
->get('doctrine')
->getManager();
}
public function testSearchByCategoryName()
{
$products = $this->entityManager
->getRepository(Product::class)
->searchByCategoryName('foo')
;
$this->assertCount(1, $products);
}
/**
* {#inheritDoc}
*/
protected function tearDown()
{
parent::tearDown();
$this->entityManager->close();
$this->entityManager = null; // avoid memory leaks
}
}
When I execute the testclass with PhpUnit I get a Doctrine\DBAL\Exception\ConnectionException with the message: "An exception occurred in driver: SQLSTATE[HY000] [1045] Access denied for user 'root'#'localhost' (using password: NO)".
I stored my database connection data in the DATABASE_URL in the .env file and the connection works fine when executing: bin/console doctrine:migrations:migrate
But it seems this configuration is not used for testing (because 'NO' is not my password in the .env file). Do I have to store the connection configuration in another file for testing? And if yes, where do I have to store the configuration, so that it gets used in my testcase?
Thanks in advance for any help!
The .env file is only used in dev environment. If you're in prod or in test, it's not even read: https://symfony.com/doc/current/configuration.html#the-env-file-environment-variables. It's clear in some parts of the doc, but less in some others, which can be confusing.
In your case, you can check your config folder, more specifically probably under config/packages/doctrine.yaml and config/packages/parameters.yaml, and see how the DATABASE_URL is used (when it exists). From there, you can either hardcode that URL in config files specific to the test environment (creating a test subfolder under config/packages for instance), or you can give the proper DATABASE_URL environment variable to phpunit "manually" by using APP_ENV=... && bin/phpunit ....
Here's what a solution would look like in the first scenario :
# config/packages/test/doctrine.yaml
doctrine:
dbal:
url: 'mysql://db_user:db_password#127.0.0.1:3306/db_name'

Laravel - setting up a test database

With my laravel application I have a bunch of migrations and db seed data.
In app/config/testing/database.php I have set a mysql database for testing.
I've populated the test database with migrate and db:seed commands, specifying the testing environment.
This works pretty well, but I want to call those commands each time I run phpunit. If it do it in the setUp then it takes so long as it's called on every single test.
I can also call it in the setUpBeforeClass which is better, but still longer if I am testing 10 classes.
Is there a way I can all it just once when I run phpunit ?
For now I have done this, in the tests/TestCase.php
class TestCase extends Illuminate\Foundation\Testing\TestCase {
public static $setupDatabase = true;
public function setUp()
{
parent::setUp();
if(self::$setupDatabase)
{
$this->setupDatabase();
}
}
public function setupDatabase()
{
Artisan::call('migrate');
Artisan::call('db:seed');
self::$setupDatabase = false;
}
....
which seems to work, but doesn't feel ideal, but means I can easily re-setup the db if I need to reset it for a test...

Class 'Eloquent' not found when mocking in Laravel

I'm following through Jeffrey Way's Laravel Testing Decoded and I've hit an issue I can't seem to fix.
I'm actually work through this tutorial: http://net.tutsplus.com/tutorials/php/testing-laravel-controllers/ Which is an excerpt from his book.
Basically I have a test like so:
class PostsTest extends TestCase {
public function __construct()
{
$this->mock = Mockery::mock('Eloquent', 'Post');
}
And that like for mocking Eloquent and Post returns:
PHP Fatal error: Class 'Eloquent' not found
When I run phpunit. Incidentally if I use Jeffrey's Laravel Generators and just generate some scaffold e.g.
php artisan generate:scaffold post --fields="title:string, body:string"
And run phpunit I get same error. He's using the same:
$this->mock = Mockery::mock('Eloquent', 'Post');
To mock the classes. Does anyone have any suggestions on what the issue could be?
I've been working through the tutorial again from scratch and am still getting the same error. I've pushed it to a public repo so people can see: https://github.com/RyanHavoc/tdd-laravel
Just pull it down, run composer install/update and phpunit.
I found a solution to the issue.
//Causes the Class 'Eloquent' not found error
public function __construct()
{
$this->mock = Mockery::mock('Eloquent', 'Post');
}
//Setting the mocks in the setUp() method instead works
public function setUp()
{
parent::setUp();
$this->mock = Mockery::mock('Eloquent', 'Post');
}

laravel 4 unit testing on windows keeps giving error

I have a Laravel 4 installation right out of the box. I am running Windows 8 64 bit with PHP 5.5, Apache 2.2 through XAMPP.
When I run phpunit I get the standard laravel error page Whoops, looks like something went wrong. and right above it I see PHPUnit 3.8-dev by Sebastian Bergmann. Configuration read from C:\project\phpunit.xml The Xdebug extension is not loaded. No code coverage will be generated.
If I delete file app/tests/ExampleTest.php then phpunit seems to work and I get
PHPUnit 3.8-dev by Sebastian Bergmann.
Configuration read from C:\project\phpunit.xml
The Xdebug extension is not loaded. No code coverage will be generated.
Time: 232 ms, Memory: 2.75Mb
←[30;43mNo tests executed!←[0m
app/tests/ExampleTest.php
<?php
class ExampleTest extends TestCase {
/**
* A basic functional test example.
*
* #return void
*/
public function testBasicExample()
{
$crawler = $this->client->request('GET', '/');
$this->assertTrue($this->client->getResponse()->isOk());
}
}
app/tests/TestCase.php
<?php
class TestCase extends Illuminate\Foundation\Testing\TestCase {
/**
* Creates the application.
*
* #return Symfony\Component\HttpKernel\HttpKernelInterface
*/
public function createApplication()
{
$unitTesting = true;
$testEnvironment = 'testing';
return require __DIR__.'/../../bootstrap/start.php';
}
}

Resources