Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Mocking and stubbing the same class instance using mockery

I have a class myModel which makes database calls. As such I want to stub this so it doesn't actually make any of these expensive calls.

public function myFunction($limit)
{
    $this->doThing();
}

private function doThing()
{
    $result = $this->myModel
        ->select('thing')
        ->groupBy('name')
        ->orderBy('count', 'desc')
        ->get;

    // do stuff with $result
}

So to stub the models methods which make the call I use

/** @test */
public function my_test()
{
    $stuff = new Collection(['person1', 'person2', 'person3',]);

    $myModelMock = m::mock(MyModel::class, [
        'select->groupBy->orderBy->get' => $stuff
    ]);

    App::instance(MyModel::class, $myModelMock);
    $myOtherClass = App::make(OtherClassWhereMyModelIsInjectedAutomagically::class);

    $myOtherClass->myFunction();
}

Which works perfectly, outputting $result as the Collection of $stuff I define in the test.

However, I also want to ensure that the fluent interface functions are only called once. I understand these functions are being called inside a private method but that shouldn't matter as I am not testing the private function itself.

So when I try and use

/** @test */
public function query_ran_once()
{
    $stuff = new Collection(['person1', 'person2', 'person3',]);

    $myModelMock = m::mock(MyModel::class, [
        'select->groupBy->orderBy->get' => $stuff,
        'where->update' => null,
        'whereIn->update' => null
    ]);

    $myModelMock
        ->shouldReceive('select->groupBy->orderBy->get')
        ->times(1)

    App::instance(MyModel::class, $myModelMock);
    $myOtherClass = App::make(OtherClassWhereMyModelIsInjectedAutomagically::class);

    $myOtherClass->myFunction();
}

I get an error which ends up being that $result is null - which means it is no longer being replaced by the $stuff data in my test.

How can the stub data be used before the mock expectations are run?

like image 987
myol Avatar asked Mar 30 '26 17:03

myol


1 Answers

Because you have to add andReturn here:

$collection = m::mock(\Illuminate\Database\Eloquent\Collection::class)
$myModelMock
    ->shouldReceive('select->groupBy->orderBy->get')
    ->times(1)
    ->andReturn($collection);

In this case it's good to return mocked Collection or Collection.

like image 97
Filip Koblański Avatar answered Apr 01 '26 09:04

Filip Koblański



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!