Laravel Testing with Modules Test setup Migrations not run? - laravel

Laravel v5.5.48
Phpunit 6.5.14
Was able to setup the test to run from the real mysql database, but of course, this is not desirable. So, changed phpunit.xml to use sqlite, but now I get "No such table" errors.
Digged for hours, but cannot get past this error.
It seems that Migrations are not getting run into the Memory Database (my theory).
It is important to mention that our application has Asgard CMS, so it has many modules (in the Modules folder) and each has its own database/migrations folder where the 'true' migrations are kept.
The migration for the table setting__settings mentioned in the error, would be in the Module/Setting/database/migrations folder.
Error info:
PHPUnit 6.5.14 by Sebastian Bergmann and contributors.
Runtime: PHP 7.3.13
Configuration: /var/www/html/phpunit.xml
E
Time: 5.93 seconds, Memory: 10.00MB
There was 1 error:
1) Tests\Unit\ExampleTest::testBasicTest
Illuminate\Database\QueryException: SQLSTATE[HY000]: General error: 1 no such table: setting__settings (SQL: select * from "setting__settings" where "name" = sitesearch::base_path limit 1)
/var/www/html/vendor/laravel/framework/src/Illuminate/Database/Connection.php:664
/var/www/html/vendor/laravel/framework/src/Illuminate/Database/Connection.php:624
/var/www/html/vendor/laravel/framework/src/Illuminate/Database/Connection.php:333
/var/www/html/vendor/laravel/framework/src/Illuminate/Database/Query/Builder.php:1719
/var/www/html/vendor/laravel/framework/src/Illuminate/Database/Query/Builder.php:1704
/var/www/html/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Builder.php:481
/var/www/html/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Builder.php:465
/var/www/html/vendor/laravel/framework/src/Illuminate/Database/Concerns/BuildsQueries.php:77
/var/www/html/Modules/Setting/Repositories/Eloquent/EloquentSettingRepository.php:86
/var/www/html/Modules/Setting/Support/Settings.php:34
/var/www/html/Modules/Setting/helpers.php:6
/var/www/html/Modules/Sitesearch/Http/frontendRoutes.php:6
/var/www/html/Modules/Core/Providers/RoutingServiceProvider.php:76
/var/www/html/vendor/laravel/framework/src/Illuminate/Routing/Router.php:389
/var/www/html/vendor/laravel/framework/src/Illuminate/Routing/Router.php:349
/var/www/html/Modules/Core/Providers/RoutingServiceProvider.php:77
/var/www/html/Modules/Core/Providers/RoutingServiceProvider.php:61
/var/www/html/vendor/laravel/framework/src/Illuminate/Routing/Router.php:389
/var/www/html/vendor/laravel/framework/src/Illuminate/Routing/Router.php:349
/var/www/html/Modules/Core/Providers/RoutingServiceProvider.php:62
/var/www/html/vendor/laravel/framework/src/Illuminate/Container/BoundMethod.php:29
/var/www/html/vendor/laravel/framework/src/Illuminate/Container/BoundMethod.php:87
/var/www/html/vendor/laravel/framework/src/Illuminate/Container/BoundMethod.php:31
/var/www/html/vendor/laravel/framework/src/Illuminate/Container/Container.php:549
/var/www/html/vendor/laravel/framework/src/Illuminate/Foundation/Support/Providers/RouteServiceProvider.php:74
/var/www/html/vendor/laravel/framework/src/Illuminate/Foundation/Support/Providers/RouteServiceProvider.php:33
/var/www/html/Modules/Core/Providers/RoutingServiceProvider.php:25
/var/www/html/vendor/laravel/framework/src/Illuminate/Container/BoundMethod.php:29
/var/www/html/vendor/laravel/framework/src/Illuminate/Container/BoundMethod.php:87
/var/www/html/vendor/laravel/framework/src/Illuminate/Container/BoundMethod.php:31
/var/www/html/vendor/laravel/framework/src/Illuminate/Container/Container.php:549
/var/www/html/vendor/laravel/framework/src/Illuminate/Foundation/Application.php:792
/var/www/html/vendor/laravel/framework/src/Illuminate/Foundation/Application.php:775
/var/www/html/vendor/laravel/framework/src/Illuminate/Foundation/Application.php:776
/var/www/html/vendor/laravel/framework/src/Illuminate/Foundation/Bootstrap/BootProviders.php:17
/var/www/html/vendor/laravel/framework/src/Illuminate/Foundation/Application.php:213
/var/www/html/vendor/laravel/framework/src/Illuminate/Foundation/Console/Kernel.php:296
/var/www/html/tests/CreatesApplication.php:18
/var/www/html/vendor/orchestra/testbench-core/src/TestCase.php:71
/var/www/html/vendor/orchestra/testbench-core/src/Concerns/Testing.php:59
/var/www/html/vendor/orchestra/testbench-core/src/TestCase.php:41
How the TestCase is extended:
namespace Tests;
use Orchestra\Testbench\TestCase as BaseTestCase;
abstract class TestCase extends BaseTestCase
{
use CreatesApplication;
}
The test itself:
namespace Tests\Unit;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Tests\TestCase;
class ExampleTest extends TestCase
{
use RefreshDatabase;
/** #test */
public function testBasicTest()
{
$this->post(route('search_results'), ['search_term' => 'calgary'])
->assertStatus(200)
->assertViewIs('sitesearch::results.index')
->assertViewHas('search_term', 'calgary');
$this->assertTrue(true);
}
}
Phpunit.xml file:
<?xml version="1.0" encoding="UTF-8"?>
<phpunit backupGlobals="false"
backupStaticAttributes="false"
bootstrap="vendor/autoload.php"
colors="true"
convertErrorsToExceptions="true"
convertNoticesToExceptions="true"
convertWarningsToExceptions="true"
processIsolation="true"
stopOnFailure="true"
verbose="true">
<testsuites>
<testsuite name="Application Test Suite">
<testsuite name="Test Suite">
<directory>./tests/Unit</directory>
<directory>./Modules/*/Tests</directory>
<!-- <directory>./tests/Feature</directory>-->
</testsuite>
<!-- <testsuite name="Modules Test Suite">-->
<!-- <directory>./Modules/*/Tests</directory>-->
<!-- </testsuite>-->
</testsuite>
</testsuites>
<!-- UN-COMMENT & RUN TO GET CODE COVERAGE-->
<!-- <logging>-->
<!-- <log type="coverage-html" target="./coverage" charset="UTF-8"-->
<!-- yui="true" highlight="true" lowUpperBound="50" highLowerBound="80"-->
<!-- showUncoveredFiles="false" />-->
<!-- </logging>-->
<filter>
<whitelist processUncoveredFilesFromWhitelist="true">
<directory suffix=".php">./Modules/*/Tests</directory>
</whitelist>
</filter>
<php>
<env name="DB_CONNECTION" value="sqlite_memory" force="true"/>
<env name="APP_ENV" value="testing"/>
<env name="APP_URL" value=""/>
<env name="CACHE_DRIVER" value="array"/>
<env name="SESSION_DRIVER" value="array"/>
<env name="QUEUE_DRIVER" value="sync"/>
</php>
</phpunit>
Also, added sqlite_memory to config/database.php:
'connections' => [
'sqlite_memory' => [
'driver' => 'sqlite',
'database' => ':memory:',
'prefix' => '',
],
'sqlite' => [
'driver' => 'sqlite',
'database' => env('DB_DATABASE', database_path('database.sqlite')),
'prefix' => '',
],

Related

I got “There is no active transaction” error after I added RefreshDatabase into test file

Making in laravel 9.48.0 with mysql database http tests after I added RefreshDatabase into test file
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Support\Facades\Artisan;
use Illuminate\Foundation\Testing\Concerns\InteractsWithExceptionHandling;
use Tests\TestCase;
use App\Models\{Article, User};
use Illuminate\Support\Str;
class ArticlesCrudTest extends TestCase
{
use InteractsWithExceptionHandling;
use RefreshDatabase;
I got “There is no active transaction” error on 1st test from 15 tests in this file
I do not use sqllite, but other mysql database, so phpunit.xml have sqlite and memory options disabled:
<?xml version="1.0" encoding="UTF-8"?>
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="./vendor/phpunit/phpunit/phpunit.xsd"
bootstrap="vendor/autoload.php"
colors="true"
printerClass="Sempro\PHPUnitPrettyPrinter\PrettyPrinterForPhpUnit9"
>
<testsuites>
<testsuite name="Unit">
<directory suffix="Test.php">./tests/Unit</directory>
</testsuite>
<testsuite name="Feature">
<directory suffix="Test.php">./tests/Feature</directory>
</testsuite>
</testsuites>
<coverage processUncoveredFiles="true">
<include>
<directory suffix=".php">./app</directory>
</include>
</coverage>
<php>
<env name="APP_ENV" value="testing"/>
<env name="BCRYPT_ROUNDS" value="4"/>
<env name="CACHE_DRIVER" value="array"/>
<!-- <env name="DB_CONNECTION" value="sqlite"/> -->
<!-- <env name="DB_DATABASE" value=":memory:"/> -->
<env name="MAIL_MAILER" value="array"/>
<env name="QUEUE_CONNECTION" value="sync"/>
<env name="SESSION_DRIVER" value="array"/>
<env name="TELESCOPE_ENABLED" value="false"/>
</php>
</phpunit>
My control have code :
\Log::info( ' -1 store::');
DB::beginTransaction();
try {
$article = Article::create([
'title' => $data['title'],
'text' => $data['text'],
'text_shortly' => $data['text_shortly'],
'creator_id' => $data['creator_id'],
'published' => $data['published'],
]);
\Log::info( ' -2 store::');
DB::Commit();
$article->load('creator');
return response()->json(
['article' => (new ArticleResource($article))],
HTTP_RESPONSE_OK_RESOURCE_CREATED
); // 201
} catch (\Exception $e) {
DB::rollback();
}
In log file there are 2 lines from this controller. Before I added RefreshDatabase these tests worked ok, just like in real work.
What is wrong ?
Thanks!

Laravel DatabaseMigration not running migrations

I'm trying to create a very simple test, where it calls a service function that executes an ::all function in a model.
EDIT: As mentioned in a comment, I put it as a feature test, but still same issue:
namespace Tests\Feature;
use App\Models\FlashCard;
use App\Services\FlashCardService;
use Illuminate\Foundation\Testing\DatabaseMigrations;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Tests\TestCase;
class ExampleTest extends TestCase
{
use DatabaseMigrations;
/**
* A basic test example.
*
* #return void
*/
public function test_the_application_returns_a_successful_response()
{
$flashCardService = new FlashCardService();
$flashCardService::getAll();
}
}
The getAll() function all it does is:
public static function getAll(): Collection {
return FlashCard::all(['id', 'question', 'answer', 'status']);
}
The problem is that I get an error that the is no such table
General error: 1 no such table: flash_cards so the DatabaseMigrations is not running.
My phpunit.xml looks like this
<?xml version="1.0" encoding="UTF-8"?>
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="./vendor/phpunit/phpunit/phpunit.xsd"
bootstrap="vendor/autoload.php"
colors="true"
>
<testsuites>
<testsuite name="Unit">
<directory suffix="Test.php">./tests/Unit</directory>
</testsuite>
<testsuite name="Feature">
<directory suffix="Test.php">./tests/Feature</directory>
</testsuite>
</testsuites>
<coverage processUncoveredFiles="true">
<include>
<directory suffix=".php">./app</directory>
</include>
</coverage>
<php>
<server name="APP_ENV" value="testing"/>
<server name="BCRYPT_ROUNDS" value="4"/>
<server name="CACHE_DRIVER" value="array"/>
<server name="DB_CONNECTION" value="sqlite"/>
<server name="DB_DATABASE" value=":memory:"/>
<server name="MAIL_MAILER" value="array"/>
<server name="QUEUE_CONNECTION" value="sync"/>
<server name="SESSION_DRIVER" value="array"/>
<server name="TELESCOPE_ENABLED" value="false"/>
</php>
</phpunit>
Any ideas?

Got "Access denied for user" when set database memory in laravel test

I'm trying to implement testing for my laravel project.
This is my phpunit.xml file:
<?xml version="1.0" encoding="UTF-8"?>
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="./vendor/phpunit/phpunit/phpunit.xsd"
bootstrap="vendor/autoload.php"
colors="true"
>
<testsuites>
<testsuite name="Unit">
<directory suffix="Test.php">./tests/Unit</directory>
</testsuite>
<testsuite name="Feature">
<directory suffix="Test.php">./tests/Feature</directory>
</testsuite>
</testsuites>
<coverage processUncoveredFiles="true">
<include>
<directory suffix=".php">./app</directory>
</include>
</coverage>
<php>
<server name="APP_ENV" value="testing"/>
<server name="APP_KEY" value="base64:in7fPzfWpFUCvr48DCZvkNf5qzqI/6SqSLpJysihepE=" />
<server name="BCRYPT_ROUNDS" value="4"/>
<server name="CACHE_DRIVER" value="array"/>
<server name="DB_CONNECTION" value="mysql"/>
<server name="DB_DATABASE" value=":memory:"/>
<server name="MAIL_MAILER" value="array"/>
<server name="QUEUE_CONNECTION" value="sync"/>
<server name="SESSION_DRIVER" value="array"/>
<server name="TELESCOPE_ENABLED" value="false"/>
</php>
</phpunit>
And I want to test database connect first, I've used RefreshDatabase trait to AutoRedirectTest (auto created when I creating project)
<?php
namespace Tests\Feature;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Support\Facades\Log;
use Tests\TestCase;
class AutoRedirectTest extends TestCase
{
use RefreshDatabase;
/**
* A basic test example.
*
* #return void
*/
public function test_home_redirect()
{
$response = $this->get('/');
$response->assertStatus(301);
$response->assertHeader('Location', '/nova');
}
}
Then when I run php artisan test, it throw error when testing AutoRedirectTest
SQLSTATE[HY000] [1044] Access denied for user 'apartment_management'#'%' to database ':memory:' (SQL: select * from information_schema.tables where table_schema = :memory: and table_name = migrations and table_type = 'BASE TABLE')
I've also tried to create new test file and add RefreshDatabase. I got the same error. But when I replace :memory: to my real database name. I've not got error above anymore.
<server name="DB_DATABASE" value="my_real_database_name"/>
So did I config something wrong?
I'm using laravel 8.61.0 with mysql 5.7.22 configured in docker.

Using Phpunit/ Why phpunit removes all data in my database

I'm trying to test my functions but everytime I try to run phpunit, it will delete all the records in my tables. I already setup my phpunit.xml file, to just in my test database, I just followed everything in the docs, do I have to setup a sqlite inmy machine, since I don't have that ? or what ? I only have laragon installed and phpmyadmin.
phpunit.xml file
<?xml version="1.0" encoding="UTF-8"?>
<phpunit backupGlobals="false"
backupStaticAttributes="false"
bootstrap="vendor/autoload.php"
colors="true"
convertErrorsToExceptions="true"
convertNoticesToExceptions="true"
convertWarningsToExceptions="true"
processIsolation="false"
stopOnFailure="false">
<testsuites>
<testsuite name="Feature">
<directory suffix="Test.php">./tests/Feature</directory>
</testsuite>
<testsuite name="Unit">
<directory suffix="Test.php">./tests/Unit</directory>
</testsuite>
</testsuites>
<filter>
<whitelist processUncoveredFilesFromWhitelist="true">
<directory suffix=".php">./app</directory>
</whitelist>
</filter>
<php>
<env name="APP_ENV" value="testing"/>
<env name="CACHE_DRIVER" value="array"/>
<env name="SESSION_DRIVER" value="array"/>
<env name="QUEUE_DRIVER" value="sync"/>
<env name="DB_CONNECTION" value="sqlite"/>
<env name="DB_DATABASE" value=":memory:"/>
</php>
</phpunit>
Be sure to use the DatabaseMigrations trait in your test classes. Eg.
use Illuminate\Foundation\Testing\DatabaseMigrations;
use Illuminate\Foundation\Testing\RefreshDatabase;
class SomeTest extends TestCase
{
use DatabaseMigrations;
use RegreshDatabase;
/**
* A basic test example.
*
* #return void
*/
public function testSomething()
{
//some code
}
}
This migrates your data on setup, and then registers a direction to roll back the migrations when the application is torn down at the end of the test.

PHPunit ignores onDelete set null in Laravel

I have a Laravel setup where I try to build everything using Test Driven Development.
Setup
I have a migration where I create a table of categories which can be a parent or child of other categories. When I delete a parent category, all the childs should become root categories. To accomplish this I created a foreign key which has set null as value for the onDelete.
Problem
When I test this behaviour in MySQL it works as expected, but when I run a test with PHPunit it fails. Can anyone help me figure out where I made a mistake or isn't this possible at all?
Migration
Schema::create('categories', function(Blueprint $table) {
$table->increments('id');
$table->string('name', 100);
$table->unsignedInteger('parent_id')->nullable();
$table->timestamps();
$table->foreign('parent_id')->references('id')->on('categories')->onDelete('set null');
});
Testfile
namespace Tests\Unit;
use App\Models\Category;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Foundation\Testing\WithFaker;
use Tests\TestCase;
class CategoryTest extends TestCase
{
/**
* #test
*/
public function aCategoryBecomesRootWhenParentIsDeleted()
{
$category = Category::create(['name' => 'test_category_6']);
$child_category = Category::create(['name' => 'test_category_7', 'parent_id' => $category->id]);
$category->delete();
$this->assertDatabaseHas('categories', ['id' => $child_category->id, 'parent_id' => NULL]);
}
}
phpunit.xml
<?xml version="1.0" encoding="UTF-8"?>
<phpunit backupGlobals="false"
backupStaticAttributes="false"
bootstrap="vendor/autoload.php"
colors="true"
convertErrorsToExceptions="true"
convertNoticesToExceptions="true"
convertWarningsToExceptions="true"
processIsolation="false"
stopOnFailure="false">
<testsuites>
<testsuite name="Unit">
<directory suffix="Test.php">./tests/Unit</directory>
</testsuite>
<testsuite name="Feature">
<directory suffix="Test.php">./tests/Feature</directory>
</testsuite>
</testsuites>
<filter>
<whitelist processUncoveredFilesFromWhitelist="true">
<directory suffix=".php">./app</directory>
</whitelist>
</filter>
<php>
<env name="APP_ENV" value="testing"/>
<env name="BCRYPT_ROUNDS" value="4"/>
<env name="DB_CONNECTION" value="sqlite"></env>
<env name="DB_DATABASE" value=":memory:"></env>
<env name="CACHE_DRIVER" value="array"/>
<env name="SESSION_DRIVER" value="array"/>
<env name="QUEUE_DRIVER" value="sync"/>
<env name="MAIL_DRIVER" value="array"/>
</php>
</phpunit>
After the comments of lagbox and Kyslik, I was able to create a solution to this problem.
My test suite uses SQLite, which has foreign keys disabled by default, apparently for backwards compatibility. To ensure my test suite is the same as my normal environment I added the following code to the TestCase class:
/**
* Enables foreign keys.
*
* #return void
*/
public function enableForeignKeys()
{
$db = app()->make('db');
$db->getSchemaBuilder()->enableForeignKeyConstraints();
}
Next, I added this line to the setup method of that same class:
$this->enableForeignKeys();
This enables me to use the foreign keys in the test environment.

Resources