Search code examples
phplaravelmockingphpunitlaravel-testing

Laravel testing. Reset controller DI while test


I have a Laravel controller with DI in

__construct(Model1 $m1, Model2 $m2, $SomeService $s) {
 $this->m1 = $m1;
 $this->m2 = $m2;
 $this->s = $s;
}

I have an API test with call or endpoint based on this controller. I'm doing 8 same API url calls with different payload. It seems z controller constructor process 1 time and after that works with constructed dependencies.

$response1 = $this->actingAs($admin,'api')->json('POST', '/api/someURL', $payload1);

$response2 = $this->actingAs($admin,'api')->json('POST', '/api/someURL', $payload2);

$responseN = $this->actingAs($admin,'api')->json('POST', '/api/someURL', $payloadN);

Can I somehow set dependencies before each API call in test?


Solution

  • You can unset the controller instance between request from the route using:

    $response1 = $this->actingAs($admin,'api')->json('POST', '/api/someURL', $payload1);
    
    // unset the controller
    $this->app->get(Illuminate\Routing\Route::class)->controller = null;
    
    $response2 = $this->actingAs($admin,'api')->json('POST', '/api/someURL', $payload2);
    
    // unset the controller
    $this->app->get(Illuminate\Routing\Route::class)->controller = null;
    
    $responseN = $this->actingAs($admin,'api')->json('POST', '/api/someURL', $payloadN);
    

    Why?

    In Illuminate\Routing\Router Laravel binds the current route to the container:

    protected function findRoute($request)
    {
        $this->current = $route = $this->routes->match($request);
        $this->container->instance(Route::class, $route);
        return $route;
    }
    

    and when the route controller is run in Illuminate\Routing\Route, the controller instance is stored in Route object:

    public function getController()
    {
        if (! $this->controller) {
            $class = $this->parseControllerCallback()[0];
            $this->controller = $this->container->make(ltrim($class, '\\'));
        }
        return $this->controller;
    }