Kaktus
Kaktus

Reputation: 153

Laravel resource controller testing gives NotFoundHttpException the second time

I am encountering a very strange thing while doing testing with Laravel 4. It looks like a bug but there's probably a logical explanation.

I have replicated the "bug" in a clean Laravel install and here's my code:

My resource controller /app/controllers/TestController.php:

(Created with php artisan controller:make TestController)

class TestController extends \BaseController {

    /**
     * Display a listing of the resource.
     *
     * @return Response
     */
    public function index()
    {
        return Response::json(array());
    }

    // The end of the file is unchanged

In my app/routes.php:

Route::get('/', function()
{
    return View::make('hello');
});

// Note the composed part of the URL.
// My problem isn't present if I just use `myapi` or `path` as a url
Route::resource('myapi/path', 'TestController');

Added in /app/test/ExampleTest.php:

public function testTest()
{
    $res = $this->call('GET', 'myapi/path');

    // Until here everything works right
    $this->assertEquals(json_decode($res->getContent()), array());

    // Now I call the same URL a second time
    $res = $this->call('GET', 'myapi/path');

    $this->assertEquals(json_decode($res->getContent()), array());
}

Now I run phpunit and here's what I get:

There was 1 error:

1) ExampleTest::testTest
Symfony\Component\HttpKernel\Exception\NotFoundHttpException: 

/home/me/Web/laraveltest/bootstrap/compiled.php:5531
/home/me/Web/laraveltest/bootstrap/compiled.php:4848
/home/me/Web/laraveltest/bootstrap/compiled.php:4836
/home/me/Web/laraveltest/bootstrap/compiled.php:4828
/home/me/Web/laraveltest/bootstrap/compiled.php:721
/home/me/Web/laraveltest/bootstrap/compiled.php:702
/home/me/Web/laraveltest/vendor/symfony/http-kernel/Symfony/Component/HttpKernel/Client.php:81
/home/me/Web/laraveltest/vendor/symfony/browser-kit/Symfony/Component/BrowserKit/Client.php:332
/home/me/Web/laraveltest/vendor/laravel/framework/src/Illuminate/Foundation/Testing/ApplicationTrait.php:51
/home/me/Web/laraveltest/app/tests/ExampleTest.php:25

In my other project I get a slightly different backtrace, but I have the impression that's the same problem: (but I have no idea of why the other is compiled and this one not)

2) UnitModelTest::testOther
Symfony\Component\HttpKernel\Exception\NotFoundHttpException: 

/home/me/Web/my-project/vendor/laravel/framework/src/Illuminate/Routing/RouteCollection.php:148
/home/me/Web/my-project/vendor/laravel/framework/src/Illuminate/Routing/Router.php:1049
/home/me/Web/my-project/vendor/laravel/framework/src/Illuminate/Routing/Router.php:1017
/home/me/Web/my-project/vendor/laravel/framework/src/Illuminate/Routing/Router.php:996
/home/me/Web/my-project/vendor/laravel/framework/src/Illuminate/Foundation/Application.php:775
/home/me/Web/my-project/vendor/laravel/framework/src/Illuminate/Foundation/Application.php:745
/home/me/Web/my-project/vendor/symfony/http-kernel/Symfony/Component/HttpKernel/Client.php:81
/home/me/Web/my-project/vendor/symfony/browser-kit/Symfony/Component/BrowserKit/Client.php:327
/home/me/Web/my-project/vendor/laravel/framework/src/Illuminate/Foundation/Testing/ApplicationTrait.php:51
/home/me/Web/my-project/app/tests/UnitModelTest.php:32

In both case the line given in the trace for the test file corresponds to the second call of the test.

As I noted in the comments of the routes.php file, if I use a simple url with no slash, the test passes without problem.

I have no problem when I use the api from the browser.

I found many topics related to the NotFoundHttpException on StackOverflow, but none looks like mine. This one is specifically present when testing and only trigger an error at the second call.

So what am I doing wrong here ? Or is it really a bug ?

Upvotes: 4

Views: 2179

Answers (2)

saeed
saeed

Reputation: 79

In my case this error happened because i change public directory name to public_html my solution was put this in the \App\Providers\AppServiceProvider register method.

public function register()
{
    // ...

    $this->app->bind('path.public', function() {
        return base_path('public_html');
    });
}

Upvotes: -1

lukasgeiter
lukasgeiter

Reputation: 152900

The problem is that calls made with the same client will use the provided URI relatively. That means what you actually call is:

  1. myapi/path
  2. myapi/myapi/path

You can fix this if you add a preface the urls with a / to make them absolute to the root of the application.

public function testTest()
{
    $res = $this->call('GET', '/myapi/path');

    // Until here everything works right
    $this->assertEquals(json_decode($res->getContent()), array());

    // Now I call the same URL a second time
    $res = $this->call('GET', '/myapi/path');

    $this->assertEquals(json_decode($res->getContent()), array());
}


If you experience other issues like that it often helps to call

$this->refreshApplication();

(This would also create a new client and therefore solve this issue as well)

Upvotes: 4

Related Questions