framework: PHPUnit testing + route bug

1. Bug description

I found a bug in laravel 4.0.10, basically when app/routes.php includes another file, and when I run phpunit, the application seems to “forget” the routes. It works fine in the first test function called, but not in the second one.

2. Steps to reproduce the bug

  • Create app/cms_routes.php
<?php
Route::get('/','HomeController@showWelcome');
  • Edit app/routes.php
<?php
require_once('cms_routes.php');
  • Edit app/tests/ExampleTest.php
<?php
class ExampleTest extends TestCase {
    public function testBasicExample()
    {
        $this->action('GET', 'HomeController@showWelcome');
        $this->assertResponseOk();
    }

    public function testBasicExample2()
    {
        $this->action('GET', 'HomeController@showWelcome');
        $this->assertResponseOk();
    }
}

3. Bug analysis

The bug occurs when cms_routes.php is included. If I put Route::get(‘/’,‘HomeController@showWelcome’); in routes.php, everything works as expected

4. Stacktrace

There was 1 error:

  1. ExampleTest::testBasicExample2 InvalidArgumentException: Unknown action [HomeController@showWelcome].

/home/mickael/work/code/www/_test/your-project-name/vendor/laravel/framework/src/Illuminate/Routing/UrlGenerator.php:263 /home/mickael/work/code/www/_test/your-project-name/vendor/laravel/framework/src/Illuminate/Foundation/Testing/TestCase.php:99 /home/mickael/work/code/www/_test/your-project-name/app/tests/ExampleTest.php:20

FAILURES! Tests: 2, Assertions: 1, Errors: 1.

About this issue

  • Original URL
  • State: closed
  • Created 11 years ago
  • Reactions: 1
  • Comments: 22 (7 by maintainers)

Most upvoted comments

It’s because you are using require_once.

It’s not a bug, I actually just ran into this, consider when you are running a class of unit rests. You have one controlling process, and it subsequently running each test in the class. Now it has to clear the environment between each test, so but when it goes to rebuild your world, it can’t re-require the other file in your web routes, because the process already has done it once. So you get route not found error’s even though you everything is clearly working. Switching from require_once will solve all the issues.

This is jus once instance of why you can’t use require once, there may be others. Don’t assume it’s a bug, perhaps especially if you are using a tool in an unintended way, and double especially if the creator of the tool said not to use it.

HTH Cheers.

Hi, I am using Laravel v 5.2.10 on Mac OSX, I have all my routes defined in the default routes.php. When I run my PHPUnit tests, I face the exception 😗* ‘InvalidArgumentException’ with message ‘Route [login] not defined.’**. and it happens only after the first call.

@taylorotwell

It’s because you are using require_once.

The answer is incorrect! Not least because in Laravel 5.3 is used require but not require_once. That is, even if you use require an bug still remains.

Here is a piece of code from Laravel 5.3 RouteServiceProvider.php file:

    protected function mapWebRoutes()
    {
        Route::group([
            'middleware' => 'web',
            'namespace' => $this->namespace,
        ], function ($router) {
            require base_path('routes/web.php');
        });
    }
    protected function mapApiRoutes()
    {
        Route::group([
            'middleware' => 'api',
            'namespace' => $this->namespace,
            'prefix' => 'api',
        ], function ($router) {
            require base_path('routes/api.php');
        });
    }

Because the bug is still there this topic should not be closed!

So to sum up, using require or require_once in routes should not be an issue at all. You should never have a loop including those file more than once.

It does make a different when running under PHPUnit, because when you have multiple test cases the application (Laravel) is being bootstrap each time within the same process/request. When you use require_once instead of require, the application can only require the route during the first test case, and simply ignores it on any subsequent tests.

Based on the initial example, you could see that everything working fine on the first test testBasicExample, but start to fail during testBasicExample2.