Context
I have a Laravel 9 (9.52.16) project (also tested on newer versions) with a custom api authentication flow. To make a request you need to receive an init_token first. This can be acquired by calling the /init path with a store_id and an api_token. The api checks if the api_token belongs to the correct store_id and returns an init token. Then it generates a new one so it can't be re-used. I have two databases. A normal one and a testing one. Inside those is a table called 'stores' where these records are stored. They are essentially copies of each other besides that the api_token fields are different.
Everything runs within docker containers using WSL (using lando to manage containers)
I have a seperate .env.testing file in my project to connect to the testing database. In phpunit 9.6.19 I have the following envs set in phpunit.xml as well
<env name="APP_ENV" value="testing"/>
<env name="BASE_URL" value="localhost:8000/"/>
<env name="STORE_ID" value="1351"/> //testing store
<env name="STORE_API_TOKEN" value="api_token_from_store_record_goes_here"/>
My entire phpunit.xml is as follows
<?xml version="1.0" encoding="UTF-8"?>
<phpunit xmlns:xsi=";
backupGlobals="false"
backupStaticAttributes="false"
bootstrap="vendor/autoload.php"
colors="true"
cacheResult="true"
executionOrder="depends"
convertErrorsToExceptions="true"
convertNoticesToExceptions="true"
convertWarningsToExceptions="true"
stopOnError="false"
stopOnFailure="false"
stopOnIncomplete="false"
stopOnSkipped="false"
stopOnRisky="false"
cacheResultFile="tests/logs/.phpunit.result.cache"
xsi:noNamespaceSchemaLocation=".3/phpunit.xsd">
<logging>
<junit outputFile="tests/logs/junit.xml"/>
</logging>
<coverage processUncoveredFiles="true">
<report>
<clover outputFile="tests/logs/clover.xml"/>
<html outputDirectory="tests/coverage"/>
</report>
<include>
<directory suffix=".php">./app</directory>
</include>
</coverage>
<testsuites>
<testsuite name="Unit">
<file>tests/Unit/EmployeeTest.php</file>
</testsuite>
<testsuite name="Feature">
<directory suffix="Test.php">./tests/Feature</directory>
</testsuite>
<testsuite name="Integration">
<directory suffix="Test.php">./tests/Integration</directory>
</testsuite>
<testsuite name="Acc">
<directory>tests/Feature/Acc</directory>
</testsuite>
</testsuites>
<listeners>
<listener class="Tests\Listeners\AccTestMessageListener"/>
</listeners>
<php>
<env name="APP_ENV" value="testing"/>
<env name="BCRYPT_ROUNDS" value="4"/>
<env name="CACHE_DRIVER" value="array"/>
<env name="MAIL_DRIVER" value="array"/>
<env name="QUEUE_CONNECTION" value="sync"/>
<env name="SESSION_DRIVER" value="array"/>
<env name="DB_CONNECTION" value="mysql"/>
<env name="TELESCOPE_ENABLED" value="false"/>
<env name="BASE_URL" value="localhost:8000/"/>
<env name="STORE_ID" value="1351"/>
<env name="STORE_API_TOKEN" value="api_token_from_store_record_goes_here"/>
</php>
</phpunit>
For my particular usecase I made a custom TestCase file that extends the default laravel TestCase. Here is a minimal version of it
<?php
namespace Tests;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Http;
class TestCaseCustom extends TestCase
{
use CreatesApplication;
private string $init_token;
private string $base_path;
private string $store_id;
private string $store_api_token;
public function setUp(): void
{
parent::setUp();
$this->base_path = env('BASE_URL');
$this->store_id = env('STORE_ID');
$this->store_api_token = env('STORE_API_TOKEN');
}
public function tearDown(): void
{
parent::tearDown();
}
public function customGet(string $url, array $params = []) {
$this->getInitToken();
}
private function getInitToken(): string
{
$response = Http::withHeaders([
'Accept' => 'application/json',
])->get($this->base_path . 'api/v1/stores/init', [
'api_token' => $this->store_api_token,
'id' => $this->store_id,
]);
dd($response->json(), env('DB_DATABASE'), DB::connection()->getDatabaseName(), config('database.connections.' . config('database.default') . '.database'));
}
}
Note the dd() function in the getInitToken function. This will be important later.
One of my testCases is as follows
public function employee_getEmployees_success()
{
$response = $this->customGet('api/v1/store/employees/' . 40);
$this->assertEquals(200, $response->getStatusCode());
$this->assertEquals("anoniem", $response->json()['output']['first_name']);
}
So basically the flow is run test -> goes to customGet function in custom TestCase file -> function requests init token and authenticates itself with the store_id and api_token -> api returns init token -> test runs call with init_token and returns the data (not in code block for simplicity)
Issue
When I run the command php artisan test --testsuite=Unit --env=testing
and it reaches the dd() function in the getInitToken() function it returns the following.
"message" => "Invalid api token"
"exception" => "Symfony\Component\HttpKernel\Exception\HttpException"
"file" => "/app/htdocs/vendor/laravel/framework/src/Illuminate/Foundation/Application.php" // tests/TestCaseCustom.php:43
[rest of stack trace]
"database_testing" // tests/TestCaseCustom.php:43
"database_testing" // tests/TestCaseCustom.php:43
"database_testing" // tests/TestCaseCustom.php:43
Note how the dd() of the env('database'), DB::connection()->getDatabaseName() and the config of the database all return database_testing. The stack trace tells me I use the invalid api token. However, when I use the api token of the normal database in my phpunit.xml it returns the expected response. This tells me it is actually connecting to the normal database instead of the testing one, but its dump the testing database?
Why is it behaving like this and how can I resolve this issue?
Things ive tried
Clear all cached config/views/routes/whatever
Make a new db connection in config/database and set '<env name="DB_CONNECTION" value="mysqlTesting"/>' in phpunit.xml
Test on newer versions of laravel and phpunit
Extend Illuminate\Foundation\Testing\TestCase instead of tests\TestCase in my custom testcase file
SSH into my container and running tests there
Run the tests via a lando command instead of in the root
Praying