Home > OS >  Call to a member function validated() on null (Unit testing Laravel 9)
Call to a member function validated() on null (Unit testing Laravel 9)

Time:01-17

I am writing test for some controller method that will validate request data and create document by 3rd party API. Then it should return response with 201 status code. I am using mocking to mock my service class that is creating document. Here is my controller:

public function margin(MarginRequest $request){
    $data = $request->validated();

    $fileId = $this->documentService->createDocument(auth()->user()->id, SignableDocumentAbstract::MARGIN_CERTIFICATE, new MarginDocument(), $data);

    return response()->json([
        'code' => 201,
        'message' => 'Margin agreement generated successfully',
        'data' => [
            'uuid' => $fileId
        ]
    ], 201);
}

And my test:

public function test_public_margin()
{
    $marginData = (new MarginFaker())->fake();

    Auth::shouldReceive('user')->once()->andReturn((object)['id' => 999999]);

    $this->mock(DocumentService::class, function (MockInterface $mock) {
        $mock->shouldReceive('createDocument')
            ->once()
            ->andReturn(Str::random());
    });

    $request = MarginRequest::create('/api/public/documents/margin', 'POST', $marginData);

    $response = app(PublicController::class)->margin($request);

    $this->assertEquals(201, $response->getStatusCode());
}

Everything look OK but when I run my test it throws error that

Call to a member function validated() on null

It is given in $data = $request->validated(); line of controller. But I can't understand why my $request is recognized as null. Even if I dump request object by dump($request) I can see that it is object and holds all required fields inside.

Then what can be the reason, why I can't call validated() method while testing?

CodePudding user response:

You do not test like that when you want to test a URL. You NEVER mock a controller or do new Controller and call a method inside it.

You have to read the HTTP Test section of the documentation.

So, your test should look like this:

public function test_public_margin()
{
    $this->actingAs(User::factory()->create());

    $this->mock(DocumentService::class, function (MockInterface $mock) {
        $mock->shouldReceive('createDocument')
            ->once()
            ->andReturn(Str::uuid());
    });

    $response = $this->post(
        '/api/public/documents/margin', 
        ['pass the needed data as an array, so the validation passes']
    );

    $response->assertStatus(201);
}
  • Related