Laravel testing with phpunit - php

How can I make sure that when I'm testing in Laravel with phpunit and for example I want to test my api route /test/1 it uses my test database?
I already made a test connection and changed my phpunit.xml file. I changed DB_CONNECTION to the test connection that I made.
<env name="DB_CONNECTION" value="mysql_testing"/>
But it when I make a post request I receive data from the development database?

In your Config/database.php file, what is the value of database in mysql_testing? It should be like this:
'mysql_testing' => [
'driver' => 'mysql',
'host' => env('DB_HOST', 'localhost'),
'port' => env('DB_PORT', '3306'),
'database' => env('TEST_DB_DATABASE', 'db_testing'),
'username' => env('DB_USERNAME', 'root'),
'password' => env('DB_PASSWORD', ''),
'charset' => 'utf8',
'collation' => 'utf8_unicode_ci',
'prefix' => '',
'strict' => false,
'engine' => null,
],
And database db_testing must exists.

Inside one of your test files, add the following to output your current DB_CONNECTION:
dd(env('DB_CONNECTION'));
You should get mysql_testing in your test output if PHPUnit.xml is properly setup.

Related

Laravel tests database migration from schema

The problem
I am using Laravel 8.83.23
I have schema dump from squashed migrations in database\schema\mysql-schema.dump
tests are running above test database, as in database.php
'testing' => [
'driver' => 'mysql',
'host' => env('DB_TEST_HOST', '127.0.0.1'),
'port' => env('DB_TEST_PORT', '3306'),
'database' => env('DB_TEST_DATABASE', 'forge'),
'username' => env('DB_TEST_USERNAME', 'forge'),
'password' => env('DB_TEST_PASSWORD', ''),
],
Before I squashed migrations, my test cases only used DatabaseMigrations trait, and the test database was recreated every time and all worked, example of test class:
class SystemControllerTest extends TestCase
{
use WithFaker;
use DatabaseMigrations;
/**
* #var User
*/
private $user;
public function setUp(): void
{
parent::setUp();
//create roles and data
$this->seed(RoleAndPermissionSeeder::class);
... etc
the migrations were found and executed, recreating the database
then, I squashed the migrations, so all migrations got deleted, and I got database\schema\mysql-schema.dump
php artisan migrate works as expected through command line, creating full database schemas from the dump (it finds it)
tests however no longer work, as there is an error
SQLSTATE[42S02]: Base table or view not found: 1146 Table 'cinema_test.roles' doesn't exist (SQL: delete from `roles`)
when I check the sql test database after the test runs, it is empty (only table migrations gets created there, and it is empty)
this error persists even when I call artisan migrate in the test's setup:
public function setUp(): void
{
parent::setUp();
Artisan::call('migrate', array(
'--database' => 'testing',
'--force' => true));
//it crashes here
$this->seed(RoleAndPermissionSeeder::class);
RoleAndPermissionSeeder just operates with the sql tables, which do not exist, hence the error
I even tried DatabaseMigrations and DatabaseTransactions and RefreshDatabase traits, without any success
how do I populate the database data? There is no way for me to read the output of the Artisan::call('migrate') command, so I do not know what is happening there
return code of Artisan::call('migrate') is 0
is there maybe some setup I am missing?
I have finally figured this out.
The reason for the problem
The problem was in incorrect setup of the testing environment. I have not discovered the exact reason, but I figured out how to setup the testing environment so that the dump would be found and loaded.
How I hunt down the bug
This describes my steps on how I found a way to fix this.
In database.php I have copied testing database instead of normal one
in database.php I had the main database connection:
'mysql' => [
'driver' => 'mysql',
'url' => env('DATABASE_URL'),
'host' => env('DB_HOST', '127.0.0.1'),
'port' => env('DB_PORT', '3306'),
'database' => env('DB_DATABASE', 'forge'),
'username' => env('DB_USERNAME', 'forge'),
'password' => env('DB_PASSWORD', ''),
'unix_socket' => env('DB_SOCKET', ''),
'charset' => 'utf8mb4',
'collation' => 'utf8mb4_unicode_ci',
'prefix' => '',
'prefix_indexes' => true,
'strict' => false,
'engine' => null,
'options' => extension_loaded('pdo_mysql') ? array_filter([
PDO::MYSQL_ATTR_SSL_CA => env('MYSQL_ATTR_SSL_CA'),
]) : [],
],
and the testing connection
'testing' => [
'driver' => 'mysql',
'host' => env('DB_TEST_HOST', '127.0.0.1'),
'port' => env('DB_TEST_PORT', '3306'),
'database' => env('DB_TEST_DATABASE', 'forge'),
'username' => env('DB_TEST_USERNAME', 'forge'),
'password' => env('DB_TEST_PASSWORD', ''),
],
I copied the testing connection data into a new mysql connection, just to see, whether on a command line I get same results
so, the file then looked like this
'mysql' => [
'url' => env('DATABASE_URL'),
'driver' => 'mysql',
'host' => env('DB_TEST_HOST', '127.0.0.1'),
'port' => env('DB_TEST_PORT', '3306'),
'database' => env('DB_TEST_DATABASE', 'forge'),
'username' => env('DB_TEST_USERNAME', 'forge'),
'password' => env('DB_TEST_PASSWORD', ''),
'unix_socket' => env('DB_SOCKET', ''),
'charset' => 'utf8mb4',
'collation' => 'utf8mb4_unicode_ci',
'prefix' => '',
'prefix_indexes' => true,
'strict' => false,
'engine' => null,
'options' => extension_loaded('pdo_mysql') ? array_filter([
PDO::MYSQL_ATTR_SSL_CA => env('MYSQL_ATTR_SSL_CA'),
]) : [],
],
/*'testing' => [
'driver' => 'mysql',
'host' => env('DB_TEST_HOST', '127.0.0.1'),
'port' => env('DB_TEST_PORT', '3306'),
'database' => env('DB_TEST_DATABASE', 'forge'),
'username' => env('DB_TEST_USERNAME', 'forge'),
'password' => env('DB_TEST_PASSWORD', ''),
],*/
on the console, I ran php artisan:migrate
the database dump was found and loaded
therefore, the dump was found in normal cases, but was not found, in testing cases
after some research, I changed the testing environment setup in phpunit.xml, I will explain it now
The file phpunit.xml
The phpunit.xml was as follows (not full file shown here):
<server name="QUEUE_CONNECTION" value="sync"/>
<server name="SESSION_DRIVER" value="array"/>
<server name="TELESCOPE_ENABLED" value="false"/>
<env name="DB_CONNECTION" value="testing"/>
</php>
</phpunit>
so, we can see that the testing database connection is defined for unit tests
on web I found advice to set the database table only, instead of changing entire connection for tests, because it is easier
I tried such an approach, so the phpunit.xml became
<server name="QUEUE_CONNECTION" value="sync"/>
<server name="SESSION_DRIVER" value="array"/>
<server name="TELESCOPE_ENABLED" value="false"/>
<env name="DB_DATABASE" value="cinema_test"/>
</php>
</phpunit>
I deleted the testing connection from database.php and related obsolete variables from .env file
this fixed the issue, and the dump file got loaded even in tests now
Conclusion
Although I have not figured out the real cause for the lavavel not loading the dump file, I have found a workaround which was to only change the database name for tests, instead of defining entirely new sql connection for testing pursposes. This solved the issue, and the database dump file gets loaded during tests now.
Seems like schema dumps can't be used for the in-memory database when testing
https://laravel.com/docs/9.x/migrations#squashing-migrations
May be able to do something like this
DB::unprepared(file_get_contents("path/file.sql"));
Would only try as a last resort, personally would want a test environment migration, also you should add a check for a test environment migration if you take this approach

How to dynamically create multiple database in laravel

I am creating Laravel 6.6 project,
my query is how to create new multiple databases in laravel and then how to handle it,
if I fetch data from the new database that I was recently created then how to register a new database in .env file dynamically?
I am doing this the following way.
I do have a dummy entry for my client connections in my config/database.php like this:
'clientDb' => [
'driver' => 'mysql',
'host' => env('DB_CLIENT_HOST', '127.0.0.1'),
'port' => env('DB_CLIENT_PORT', '3306'),
'database' => env('DB_CLIENT_DATABASE', 'some_default_client_name'),
'username' => env('DB_CLIENT_USERNAME', 'root'),
'password' => env('DB_CLIENT_PASSWORD', ''),
'unix_socket' => env('DB_CLIENT_SOCKET', ''),
'charset' => 'utf8mb4',
'collation' => 'utf8mb4_unicode_ci',
'prefix' => '',
'strict' => false,
'engine' => null,
'dump' => [],
],
So, all my client-related models are used with $connection = 'clientDb';, the others using the default connection.
When changing a client (so i need to switch the connection), i just set the new connection by calling:
Config::set('database.connections.clientDb', [
'database' => NEW_DATABASE_NAME,
// all the other params from config
]);
After that, i figured out to call DB::reconnect('clientDb'); to get the connection really running.
I hope, this will lead you to the right direction 😉
You should usage from database.php in config directory. for example I have another mysql database which is different from main db:
so I add this code to database.php and connections section:
'mysql_second_db' => [
'driver' => 'mysql',
'host' => env('DB_HOST_SECOND_DB', '127.0.0.1'),
'port' => env('DB_PORT_SECOND_DB', '3306'),
'database' => env('DB_DATABASE_SECOND_DB', 'forge'),
'username' => env('DB_USERNAME_SECOND_DB', 'forge'),
'password' => env('DB_PASSWORD_SECOND_DB', ''),
'unix_socket' => env('DB_SOCKET', ''),
'charset' => 'utf8',
'collation' => 'utf8_general_ci',
'prefix' => '',
'prefix_indexes' => true,
'strict' => true,
'engine' => null,
],
You can use that:
$names=['name1','name2'];
Schema::create('t1', function($table)
{
$table->increments('id');
});
To set env look at that: ENV

Laravel: use database created in WAMP

I created a database using WAMP. Now I have to move everything to Laravel.
How can I use this database?
I have a lot of stored procedures written there, I would really like to use them again.
I tried changing .env file and config/database.php file, but it won't help.
config/database.php
'driver' => 'mysql',
'host' => env('DB_HOST', '127.0.0.1'),
'port' => env('DB_PORT', '3306'),
'database' => env('DB_DATABASE', 'db_file'),
'username' => env('DB_USERNAME', 'root'),
'password' => env('DB_PASSWORD', 'psi'),
'unix_socket' => env('DB_SOCKET', ''),
'charset' => 'utf8',
'collation' => 'latin2_general_ci',
'prefix' => '',
'strict' => true,
'engine' => null,
.env:
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=db_file
DB_USERNAME=root
DB_PASSWORD=psi
You don`t need to configure both env and database.php.Configure one.I recommend you to configure env file .You need a model to access the database.
Models-
https://laravel.com/docs/5.4/eloquent
Controllers-
https://laravel.com/docs/5.4/controllers#resource-controllers
Always follow the documentation

laravel5 | Homestead | Auth Registration and login is not connect with Database

I'm using laravel5 with Homestead (homestead.app).
At beginning i use localhost, that time laravel Auth working fine.
But move to homestead, its not working(cant connect with DB).
Any configurations need to change ?
MYSQL : Connection
DB_HOST=localhost
DB_DATABASE=laravel5
DB_USERNAME=homestead
DB_PASSWORD=secret
First ensure you really have .env file uploaded to the host.
The .env file is used by config/database.php file.
Ensure that it contains a line
'default' => env('DB_CONNECTION', 'mysql'),
and these lines as well:
'connections' => [
//...
'mysql' => [
'driver' => 'mysql',
'host' => env('DB_HOST', 'localhost'),
'database' => env('DB_DATABASE', ''),
'username' => env('DB_USERNAME', ''),
'password' => env('DB_PASSWORD', ''),
'charset' => 'utf8',
'collation' => 'utf8_unicode_ci',
'prefix' => '',
'strict' => false,
],
//...
],

Laravel different config/database.php for production and development

I'm developing Laravel app on my local server where I have database and also I'm putting in online in production environment.
Each environment has different db connection information. So far I dealt with this just commenting information when I'm committing like this:
'mysql' => [
'driver' => 'mysql',
'host' => $host,
'database' => $database,
'username' => $username,
'password' => $password,
// 'host' => env('DB_HOST', 'localhost'),
// 'database' => env('DB_DATABASE', 'forge'),
// 'username' => env('DB_USERNAME', 'forge'),
// 'password' => env('DB_PASSWORD', ''),
// 'unix_socket' => '/Applications/MAMP/tmp/mysql/mysql.sock',
'charset' => 'utf8',
'collation' => 'utf8_unicode_ci',
'prefix' => '',
'strict' => false,
],
but this is sure wrong approach. How can I set different database connection information for each environment is some better way?
Use the .env file instead.. Have a .env in your production and one in your development..
Take a look at your .env.example
Laravel Environment Configuration Documentation

Categories