Gustavo Straube
Gustavo Straube

Reputation: 3861

How to mock an aliased class with a method that returns an instance of itself?

I've been successfully using Mockery with PHPUnit tests lately. Yet, there is a dependency in a project I'm currently working that uses static method calls to interact with an API. I'm struggling to test one particular use case and it feels like I'll find other like this during the development roadmap.

Using this class as an example:

namespace Name\Space;
class User
{
    /**
     * @return \Name\Space\User[]
     */
    public static function list(): array
    {
        // ...
    }
    public static function create(array $attrs): User
    {
        // ...
    }
}

In case I just want to assert a method returns a primitive type, such as an array:

Mockery::mock('alias:\Name\Space\User')
    ->shouldReceive('list')
    ->andReturn([]);

It works fine, primarily because I'm not testing the array contents.

However, I have to call the create method, which returns an instance of the class itself (User). If I do something like this:

$user = new \Name\Space\User();
Mockery::mock('alias:\Name\Space\User')
    ->shouldReceive('create')
    ->andReturn($user);

The alias, obviously, won't work because the class was already loaded through the autoloader (composer's, in this case).

Does anyone have a suggestion on how to workaround this?

Upvotes: 6

Views: 2379

Answers (2)

SilvioQ
SilvioQ

Reputation: 2072

What about creating User in a closure?

<?php

$user = Mockery::mock('overload:\Name\Space\User')
    ->shouldReceive('create')
    ->andReturnUsing(function() {
              return new \Name\Space\User();
    });

Upvotes: 4

sfeldmann
sfeldmann

Reputation: 357

Mocking static stuff is always painful. I would recommend creating a Proxy object that is calling the static API calls and just returns the API results and inject this object everywhere you need to call the API.

This way it is easy to test by simply mocking the proxy object.

The proxy object itself can then be tested in an end to end test outside of the pure unit test scope.

You can still do more invasive stuff like this https://www.pagemachine.de/blog/mocking-static-method-calls/?cn-reloaded=1

But writing code that doesn't belong to your unit tests purely to make something testable doesn't feel right to me.

Upvotes: 0

Related Questions