How to mock static methods of a Laravel Eloquent model?

10,773

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); 
Share:
10,773

Related videos on Youtube

Zed
Author by

Zed

Updated on September 15, 2022

Comments

  • Zed
    Zed over 1 year

    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.

    • Nathan Koop
      Nathan Koop almost 8 years
      Is it a typo? ->andReturn(...);
  • Zed
    Zed almost 8 years
    Hmm, I tried with your approach, but this is what I get back Mockery\Exception\RuntimeException: Could not load mock App\Models\ModelName, class already exists . I've added @runTestsInSeparateProcesses and @preserveGlobalState as well.
  • Marcin Nabiałek
    Marcin Nabiałek almost 8 years
    @Zed You should make sure it's a very first line in your test. In case you already so something else with ModelName - either directly in method or in other places (for example setUp method) it won't work because it will first create real object and won't be able to overload it next time.
  • Fredrik Schöld
    Fredrik Schöld almost 8 years
    When mocking public static method calls you should use alias:App\Models\ModelName not overload:\Models\ModelName. overload is used to intercept and mock class instantiation (new class() for instance) and alias is used for public static methods (Class::method).
  • Marcin Nabiałek
    Marcin Nabiałek almost 8 years
    @Zed If you still have this problem, you might look at my updated answer
  • Moses Ndeda
    Moses Ndeda over 6 years
    Worked a bit for me :-)
  • Zhi V
    Zhi V about 4 years
    /** * @runInSeparateProcess * @preserveGlobalState disabled */