14
votes

i am new in Laravel. Using local development environment with Homestead Try to run simple test

namespace Tests\Feature;

use Tests\TestCase;
use Illuminate\Foundation\Testing\RefreshDatabase;

class UserTest extends TestCase
{
    /**
     * A basic test example.
     *
     * @return void
     */

    public function testBasicTest()
    {
        $response = $this->get('/');

        $response->assertStatus(200);
    }
}

routes/web.php :

Route::get('/', function () {
    return view('main');
});

Auth::routes();

Route::get('/home', 'HomeController@index')->name('home');

running phpunit returns 404 error

vagrant@homestead:~/code/laravel$ phpunit PHPUnit 6.4.3 by Sebastian Bergmann and contributors.

.F. 3 / 3 (100%)

Time: 1.07 seconds, Memory: 10.00MB

There was 1 failure:

1) Tests\Feature\UserTest::testBasicTest Expected status code 200 but received 404. Failed asserting that false is true.

/home/vagrant/code/laravel/vendor/laravel/framework/src/Illuminate/Foundation/Testing/TestResponse.php:78 /home/vagrant/code/laravel/tests/Feature/UserTest.php:25

I have tried to fix it with these ways

1. Laravel phpunit always 404 updateTestCase.php

    protected $baseUrl = 'http://localhost'

change with

    protected $baseUrl = 'http://laravel.local'

2. https://github.com/dingo/api/issues/540 and next to it https://github.com/dingo/api/issues/571

    use Illuminate\Foundation\Testing\WithoutMiddleware;
    class BankTest extends TestCase {
        use WithoutMiddleware;
  1. Changing APP_URL in .env to

    APP_URL=laravel.local
    

none of this helped

'laravel.local' works fine in browser

Please, help me fix it

8
Can you post your routes file?FatBoyXPC
@FatBoyXPC, added routes to questionИлья Алисов
Which version of Laravel is this?FatBoyXPC
@FatBoyXPC, 5.5.19Илья Алисов
Have you tried putting http:// in front or the url in APP_URL? I tried to run my tests without http:// and they failed. I don't have $baseUrl in my TestCase at all, just FYI.FatBoyXPC

8 Answers

15
votes

I was running my application with following URL in browser. http://localhost/app/public/

The default unit test having below line was failing. It was getting 404 response instead of 200.

$response = $this->get('/'); $response->assertStatus(200);

I changed APP_URL in .env file as below after reading above comments.

APP_URL=http://localhost

But I was still getting 404 error. After some trial and errors, I found that I needed to clear config cache.

php artisan config:cache

This did the trick and my test started working!!

7
votes

I had the same problem, and if I run laravel with php artisan serve, it has to be:

APP_URL=http://127.0.0.1:8000/

The APP_URL, has to be exactly the URL of the website.

The website was working, but I didn't have that constant correctly, and PHPUnit was saying all time 404.

Don't forget to clear the cache, after change the config

php artisan config:cache
4
votes

Have you tried with process isolation set to true in your phpunit.xml file? Our functional tests fail with 404 errors all over the place if we do not have process isolation:

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

For anyone having this problem, use APP_URL=http://localhost, this happens if you use vagrant I am not sure for other envs, still investigating.

2
votes

Laravel tests run and expect environment variables. They expect variables like ENV_URL, ENV_KEY,... depending on your test case. It is important that the ENV_URL variable is set to http://localhost disregarding your laravel/server setup. Tests work differently here.

Inside phpunit.xml, the line <server name="APP_ENV" value="testing"/> specifies which testing file to use. value="testing" expects a to use the .env.testing file, if it exists and fallbacks to .env.

There are two approaches that you can do from here on:

Approach A - Using .env.testing:

  1. Create a copy of .env and name it .env.testing.
  2. Verfiy that phpunit.xml includes the .env.testing file, like following <server name="APP_ENV" value="testing"/>
  3. IMPORTANT Edit the .env.testing to use APP_URL=http://localhost as its URL. It doesn't matter under which URL you usually serve your application.
  4. Edit other values to reflect your testing environment
  5. Delete cache using php artisan cache:clear

Approach B - ENV values in phpunit.xml:

You can harcode all ENV values inside the phpunit.xml, like below

   ...
    <php>
        <server name="APP_URL" value="http://localhost"/>
        <server name="APP_KEY" value="base64:e8+BZAzKrSR/LprdHQ2TfMaw+DOTWYmgpkFkEJHV+zw="/>
        <server name="DB_CONNECTION" value="mysql"/>
        <server name="DB_HOST" value="127.0.0.1"/>
        <!-- More ENV values -->
        ...
        <server name="BCRYPT_ROUNDS" value="4"/>
        <server name="CACHE_DRIVER" value="array"/>
        <!-- <server name="DB_CONNECTION" value="sqlite"/> -->
        <!-- <server name="DB_DATABASE" value=":memory:"/> -->
        <server name="MAIL_MAILER" value="array"/>
        <server name="QUEUE_CONNECTION" value="sync"/>
        <server name="SESSION_DRIVER" value="array"/>
        <server name="TELESCOPE_ENABLED" value="false"/>
    </php>
</phpunit>

Bonus - Hybrid Approach:

Use the main .env file and overwrite the APP_URL inside the phpunit.xml. For this, there should not exist an .env.testing file or remove <server name="APP_ENV" value="testing"/> if it does exist.

   ...
    <php>
        <server name="APP_ENV" value="testing"/>

        <!-- IMPORTANT - Overwrite the APP_URL -->
        <server name="APP_URL" value="http://localhost"/> 

        <server name="BCRYPT_ROUNDS" value="4"/>
        <server name="CACHE_DRIVER" value="array"/>
        <!-- <server name="DB_CONNECTION" value="sqlite"/> -->
        <!-- <server name="DB_DATABASE" value=":memory:"/> -->
        <server name="MAIL_MAILER" value="array"/>
        <server name="QUEUE_CONNECTION" value="sync"/>
        <server name="SESSION_DRIVER" value="array"/>
        <server name="TELESCOPE_ENABLED" value="false"/>
    </php>
</phpunit>
0
votes

As @TooCooL mentioned, one could set APP_URL=http://localhost even if your project might be something as APP_URL=http://localhost/myproject.
Even better is to create another .env, it shall be called env.testing and there one can change APP_URL or even another database for testing purposes only and so on.
Phpunit will look for configuration at that file .env.testing
Although phpunit works fine even when APP_URL is set on my vhost name on my lamp stack.
Check out your /etc/hosts file as well.

0
votes

The solution is to simply test using the url returned by

php artisan serve

as base url then run the tests

For example:

    $response = $this->post('http://127.0.0.1:8001/api/register', [
        'email' => '',
        'phone' => '',
        'password' => '',
        'c_password' => '',
        'role_id' => '',
    ]);

    $response->assertStatus(401);
0
votes

Just for Laravel 8 devs.

Use full url inside get method

 $response = $this->get('http://127.0.0.1:8000');