0

To test below method

public function handle($loginDetails): User
{
    $authUser = $this->user->where('user_id', $loginDetails->id)->first();
    if (!$authUser) {
        $authUser = $this->user->create([
            'name' => $loginDetails->name,
            'email' => $loginDetails->email,
            'profile_image' => $loginDetails->avatar_original,
            'user_id' => $loginDetails->id
        ]);
    }

    return $authUser;
}

I am mocking and testing it as below

public function shouldHandleNewUser()
{
        $mockBuilder = $this->getMockBuilder(Builder::class)
            ->disableOriginalConstructor()
            ->setMethods(['first'])
            ->getMock();
        $mockBuilder->method('first')
            ->willReturn(null);

        $mockUser = $this->getMockBuilder(User::class)
            ->disableOriginalConstructor()
            ->setMethods(['where', 'create'])
            ->getMock();

        $mockUser->method('where')
            ->willReturn($mockBuilder);

        $mockUser->method('create')
            ->willReturn(new User());

        $loginDetails = new class {
            public $id = 1;
            public $name = 'testUser';
            public $email = '[email protected]';
            public $avatar_original = 'http://someurl.com/image.jpg';
        };

        $registrationHandler = new RegistrationHandler($mockUser);
        $this->assertInstanceOf(User::class, $registrationHandler->handle($loginDetails));
}

When it reaches to the create method it is throwing

PHPUnit_Framework_MockObject_BadMethodCallException

What I am doing wrong here ?

0

1 Answer 1

2

You can't mock static methods with PHPUnit (I'm assuming User::create() is static).

Limitation: final, private, and static methods

Please note that final, private, protected, and static methods cannot be stubbed or mocked. They are ignored by PHPUnit's test double functionality and retain their original behavior.

There used to be a staticExpects() method to work around it. It was deprecated in PHPUnit 3.8 and removed in PHPUnit 3.9. As Sebastian Bergmann says, the solution is to not use static methods (and I agree with him)

Sign up to request clarification or add additional context in comments.

4 Comments

You are correct, It happens to be a static method in Laravel Eloquent. Any work around ?
The problem with Eloquent models is that they're actually implementations of an Active Record pattern, which means they tightly couple persistence and business logic, and they're full of static methods, which make the classes really hard to test. If you're able to use Mockery (I think it comes with Laravel), take a look at this question.
Thanks for explanation. I changed my code from using static create method to a instance method in Eloquent save. I kinda feel bad by changing code to satisfy the test. But your explanation cleared my concept. thanks
Raheel, I think refactoring is a big part of coding, so don't feel bad! That said, there's a lot of information on unit testing Eloquent Models (I've seen people just do integration testing on them instead of unit testing), so definitely try to find some articles, maybe you can keep your code! Here are some: first, second. Good luck!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.