Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to mock static methods of a Laravel Eloquent model?

I have in my code a line like this:

ModelName::create($data);

where ModelName is just an Eloquent model. Is there a way to mock this call inside a unit test? I tried with:

$client_mock = \Mockery::mock('Eloquent','App\Models\ModelName');
$client_mock->shouldReceive('create')
            ->with($data)->andReturns($returnValue);

but it doesn't work.

like image 874
Zed Avatar asked May 26 '16 09:05

Zed


People also ask

Is mocking static methods bad?

If you need to mock a static method, it is a strong indicator for a bad design. Usually, you mock the dependency of your class-under-test. If your class-under-test refers to a static method - like java.

Can static classes be mocked?

Because there is no instance variable, the class name itself should be used to access the members of a static class. The powerful capabilities of the feature-rich JustMock framework allow you to mock static classes and calls to static members like methods and properties, set expectations and verify results.

What is static method in laravel?

Therefore, any logic which can be shared among multiple instances of a class should be extracted and put inside the static method. PHP static methods are most typically used in classes containing static methods only often called utility classes of PHP frameworks like Laravel and CakePHP.

What is mockery in laravel?

When testing Laravel applications, you may wish to "mock" certain aspects of your application so they are not actually executed during a given test. For example, when testing a controller that dispatches an event, you may wish to mock the event listeners so they are not actually executed during the test.


1 Answers

You should do something like this:

$client_mock = \Mockery::mock('overload:App\Models\ModelName');
$client_mock->shouldReceive('create')->with($data)->andReturn($returnValue);

We are using overload: because you don't want to pass mock to some class, but you want to use it also in case it's hard-coded into some classes.

In addition to your test class (just before class) you should add:

/**
 * @runTestsInSeparateProcesses
 * @preserveGlobalState disabled
 */

to avoid errors that this class was already loaded (it might work without it in single test but when you are running multiple tests probably it won't).

You might read Mocking hard dependencies for details about it.

UPDATE

In some cases it might be not possible to mock classes using this method. In those cases you can create a normal mock (without overload) and inject it to the service container like so:

App::instance('\App\Models\ModelName', $client_mock); 
like image 163
Marcin Nabiałek Avatar answered Oct 17 '22 18:10

Marcin Nabiałek