Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Post bodies ignored when making multiple post calls in laravel test

I've been running into problems writing my phpunit tests in lumen5.2 with laravel components. If I make multiple http calls to my API within a single test,the body I supply for subsequent calls is ignored in favor of the first body supplied to any http call in the test. The problem occurs using any of the available methods in MakesHttpRequests, such as post() or put() or call(). The problem is similar but not identical to issues discussed here and here, but their solutions are not applicable or don't fix my issue. I've distilled it down to the following behavior:

EchoTest.php

<?php

class EchoTest extends TestCase
{
    public function testEcho()
    {
        $this->json('POST', '/echo', ['string' => "first"]);
        $this->json('POST', '/echo', ['string' => "second"]);
        $this->json('POST', '/echo', ['string' => "third"]);
    }
}

EchoController.php

<?php

namespace App\Http\Controllers;

use App\Http\Controllers\Controller;
use Illuminate\Support\Facades\Input;

class EchoController extends Controller
{
    public function _echo()
    {
        $input = Input::json()->all();
        var_dump($input['string']);
    }
}

routes.php

<?php

$app->post('echo', ['uses' => 'EchoController@_echo']);

Output

.string(5) "first"
string(5) "first"
string(5) "first"

I've found that calling $this->refreshApplication() after each post call helps somewhat, but also breaks the DatabaseTransactions logic, leaving the database littered with test data that contaminates subsequent test runs, and also having off-by-one side effects like not fixing the problem for the last post before the refresh.

I'm rather stumped on what I'm doing wrong here. I've traced the request handling down several layers until I lose it in all the container magic underneath and can't find any obvious bugs there.

like image 647
Nathan Clow Avatar asked May 24 '16 15:05

Nathan Clow


People also ask

What is unit testing in Laravel?

Unit tests are tests that focus on a very small, isolated portion of your code. In fact, most unit tests probably focus on a single method. Tests within your "Unit" test directory do not boot your Laravel application and therefore are unable to access your application's database or other framework services.

How do I run a test in Laravel?

After installing a new Laravel application, execute the vendor/bin/phpunit or php artisan test commands to run your tests. When running tests, Laravel will automatically set the configuration environment to testing because of the environment variables defined in the phpunit.xml file.

What is the Laravel test assertions package?

The Laravel Test Assertions package offers an option to quickly knock off the main points and gives us confidence that everything is wired up correctly. With the basics covered we can focus on more complex parts of the application like custom validation rules or the business logic of the application. Keep testing until you have confidence.

How many records are created with the factory method in Laravel?

As you can see we use the Post model and we say that it creates 120 records with the factory method if you use another version of Laravel the syntax may change but you can see it in the official documentation.


1 Answers

After a great deal of trial and error, I found that calling Facade::clearResolvedInstances() after every http call makes successive http calls work properly. This seems to avoid the side-effects of breaking database transactions that come from refreshApplication. I ended up wrapping all the http verb methods to automatically call the method in this manner:

public function get($uri, array $headers = [])
{
    $ret = parent::get($uri, $headers);
    Facade::clearResolvedInstances();
    return $ret;
}

I still have no idea why such a thing is necessary.

like image 68
Nathan Clow Avatar answered Oct 06 '22 06:10

Nathan Clow