PWParsons's avatar

How to test a view composer

I'm new to testing so please forgive me if I am missing something obvious.

I'm trying to test the following view composer:

namespace App\Http\View\Composers;

use App\Models\Category;
use Illuminate\View\View;

class CategoryComposer
{
    public function compose(View $view)
    {
        $view->with(
            'categories',
            Category::getParents()
        );
    }
}

The test:

class CategoryComposerTest extends TestCase
{
    /** @test **/
    public function it_passes_the_parent_categories_to_the_view(): void
    {
        $composer = new CategoryComposer;

        $view = $this->mock(View::class);

        $view->shouldReceive(['with'])
            ->with([
                'categories',
                Category::getParents()
            ])
            ->once();

        $composer->compose($view);
    }
}

The following error occurs when running the test:

Mockery\Exception\BadMethodCallException : Received Mockery_2_Illuminate_View_View::with(), but no expectations were specified

What am I doing wrong?

0 likes
4 replies
drewdan's avatar

I don't think you need that shouldRecieve as an array

$view->shouldReceive('with')
            ->with([
                'categories',
                Category::getParents()
            ])
            ->once();
PWParsons's avatar

Hey @drewdan , thanks for your reply.

I originally had the parameter as a string and it didn't work. I just changed it to a string because to remove the Expected parameters of type array|array[]warning in PHPStorm.

drewdan's avatar

I managed to use this in my test

$mock = $this->mock(View::class);
$mock->shouldReceive('with')->with('some data')->andReturns('foo');

You do not need to pass it as an array unless you are using more than one item. The interface looks like this:

 /**
     * Set expected method calls
     *
     * @param string|array ...$methodNames one or many methods that are expected to be called in this mock
     *
     * @return \Mockery\ExpectationInterface|\Mockery\Expectation|\Mockery\HigherOrderMessage
     */
    public function shouldReceive(...$methodNames);

As its not type hinting an array, it does not need to have an array, but if it has an array, it will use the spread function to pass this method multiple parameters.

Alas though, from the look of it, this does not appear to be your issue.

Maybe try accepting any args for now, see if we can get the test passing that way:

$view->shouldReceive('with')
            ->withAnyArgs()
	    ->andReturn('foo');
PWParsons's avatar

The following works right...

/** @test */
    public function it_passes_the_parent_categories_to_the_view(): void
    {
        $composer = new CategoryComposer;
        $view = $this->spy(View::class);

        $composer->compose($view);

        $view->shouldHaveReceived('with')->once();
    }

it fails when checking if the correct data is passed to the view...

$view->shouldHaveReceived('with')
            ->with('categories', Category::getParents())
            ->once();

the error:

Mockery\Exception\InvalidCountException : Method with(<Any Arguments>) from Mockery_2_Illuminate_View_View should be called at least 1 times but called 0 times.

Please or to participate in this conversation.