Search code examples
phplaraveltestingphpunitlaravel-7

PHPunit tests on Laravel routes always returns 404


I just began writing PHPUnit route tests on my laravel application and it's working fine via browser and Postman, not via PHPunit though.

Example: on this test

public function test_getAll(){
    $this->withoutExceptionHandling(); // If i comment this line I get the 404 and not the error shown below

    $response = $this->get('/api/users');
    $response->assertStatus(401);
}

I get:

PHPUnit 8.5.3 by Sebastian Bergmann and contributors.

.E                                                                  2 / 2 (100%)

Time: 1.89 seconds, Memory: 8.00 MB

There was 1 error:

1) Tests\Feature\Users\UserRoute_SuperAdminTest::test_getAll
Symfony\Component\HttpKernel\Exception\NotFoundHttpException: GET http://localhost/cms/api/users

E:\www\projects\cms-php\vendor\laravel\framework\src\Illuminate\Foundation\Testing\Concerns\InteractsWithExceptionHandling.php:126
E:\www\projects\cms-php\vendor\laravel\framework\src\Illuminate\Foundation\Http\Kernel.php:415
E:\www\projects\cms-php\vendor\laravel\framework\src\Illuminate\Foundation\Http\Kernel.php:113
E:\www\projects\cms-php\vendor\laravel\framework\src\Illuminate\Foundation\Testing\Concerns\MakesHttpRequests.php:468
E:\www\projects\cms-php\vendor\laravel\framework\src\Illuminate\Foundation\Testing\Concerns\MakesHttpRequests.php:258
E:\www\projects\cms-php\tests\Feature\Users\UsersRoute-SuperAdmin_Test.php:45

The weird thing is: if i change the URL to:

$response = $this->get('http://anythingatallinhere/api/users');

I get the 401 response that I should.

More context info to solve the problem.

My env APP_URL is APP_URL=http://localhost/cms and I am registering routes dynamically this way: I have a CoreServiceProvider with a boot procedure like this:

public function boot()
    {
       [...]
        $moduleController = app()->make(ModuleController::class);
        $moduleController->registerCoreRoutes();
       [...]
    }

on ModuleController:

function registerCoreRoutes(){
        foreach($this->allValidated as $moduleAlias => $registeredModule){
            $modName = ucfirst(str_replace('core/', '', strtolower($moduleAlias)));
            $namespace = 'App\Api\Core' . '\\' . $modName . '\Controllers';

            try {
                foreach ($registeredModule['routerFiles'] as $key => $routerInfo){
                    $routePath = app_path('Api/Core/' . $modName . '/Routes/' . $routerInfo['fileName'] . '.php');
                    $prefix = 'api/' . $routerInfo['path'];

                    $this->pathToModule[$routerInfo['path']] = $moduleAlias;

                    Route::prefix($prefix)
                        ->namespace($namespace)
                        ->group($routePath);
                }
                $this->allRegistered[$moduleAlias] = $registeredModule;
            } catch (\Throwable $th) {
                var_dump('Core module route registration failed');
                $this->allRegistered = [];
                throw $th;
            }
        }
    }

If I use php artisan route:list they are all there properly registered as well.


Solution

  • I had a similar problem recently but it worked after running these:

    php artisan config:clear
    php artisan config:cache
    

    Especially if you changed the just changed the APP_URL in your .env file.

    You could also try setting processIsolation to true in your phpunit.xml file:

    <phpunit backupGlobals="false"
     backupStaticAttributes="false"
     bootstrap="bootstrap/autoload.php"
     colors="true"
     convertErrorsToExceptions="true"
     convertNoticesToExceptions="true"
     convertWarningsToExceptions="true"
     processIsolation="true"
     stopOnFailure="false">
    

    EDIT: If none of the above works, you could also create another .env.testing and set your APP_URL to http://localhost. PHPUnit will use variables from that file. This works regardless of the actual URL of your application