最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

php - Custom phpunit TestCase does not recognize .env.testing in my Laravel project - Stack Overflow

programmeradmin3浏览0评论

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

发布评论

评论列表(0)

  1. 暂无评论