Laravel资源控制器测试第二次给出NotFoundHttpException

时间:2014-12-27 18:17:27

标签: php exception laravel laravel-4 phpunit

我在使用Laravel 4进行测试时遇到了一个非常奇怪的事情。它看起来像一个bug,但可能有一个合乎逻辑的解释。

我在一个干净的Laravel安装中复制了“bug”,这是我的代码:

我的资源控制器/app/controllers/TestController.php

(使用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

在我的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');

/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());
}

现在我运行phpunit,这就是我得到的:

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

在我的另一个项目中,我得到了一个稍微不同的回溯,但我的印象是同样的问题:(但我不知道为什么另一个被编译而且这个没有)

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

在这两种情况下,测试文件的跟踪中给出的行对应于测试的第二 call

正如我在routes.php文件的注释中所指出的,如果我使用一个没有斜杠的简单网址,那么测试会毫无问题地通过。

当我使用浏览器中的api时,我没有问题。

我发现很多与StackOverflow上的NotFoundHttpException相关的主题,但没有一个看起来像我的。这个在测试时特别存在,只在第二次调用时触发错误。

那我在这里做错了什么?或者它真的是一个错误?

2 个答案:

答案 0 :(得分:4)

问题是由同一客户端创建的call将相对使用提供的URI。这意味着你实际上称之为:

  1. myapi /路径
  2. myapi / myapi /路径
  3. 如果您使用/添加网址前言,以使其对应用程序的根目录是绝对的,则可以解决此问题。

    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());
    }
    


    如果您遇到其他问题,通常会有助于调用

    $this->refreshApplication();
    

    (这也会创建一个新的client,因此也解决了这个问题)

答案 1 :(得分:0)

在我的情况下,发生此错误是因为我将public目录名更改为public_html,而我的解决方案却被放置在\App\Providers\AppServiceProvider register方法中。

public function register()
{
    // ...

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