Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Mockery::mock on Redis (php extension) can't mock eval method: should blacklisted methods raise an error when an expectation is set for them? #1159

Open
mfn opened this issue Jan 11, 2022 · 2 comments

Comments

@mfn
Copy link
Contributor

mfn commented Jan 11, 2022

Me and my co-worker had some fun today figuring out why:

  • I could mock \Redis (the PHP extension)
  • could specify an expectation for the method eval
  • but whenever the eval method on the mocked instance was called, we straight received a RedisException: Redis server went away in …

To give an example, assuming mockery being installed and use this test script:

<?php
require __DIR__ . '/vendor/autoload.php';

$redisMock = Mockery::mock(Redis::class);
$redisMock->shouldReceive('eval');
$redisMock->eval('test');

Without extension loaded:

$ php test.php
$

Run it with redis extension loaded:

$ php -d extension=redis test.php

Fatal error: Uncaught RedisException: Redis server went away in test.php:6

There are some obvious things like eval being reserved, you can't even use it as class method. The PHP extension can however it is definitely an outlier.

The solution in this case was simply to use a custom MockConfigurationBuiler and a custom list of methods to pass to setBlackListedMethods which does not include eval and it just works.

But I was wondering

When a method is disallowed to be used for mocking and part of the list, shouldn't any expectation set on such a method actually raise an error maybe? Because effectively it can't work 🤔

Thanks!

@ghostwriter
Copy link
Member

Hey @mfn

Mocker has a syntax for getting around a reserved word in PHP.

Mockery::mock(Redis::class . '[eval]');

you may also, as you previously mentioned, use MockConfigurationBuilder::setBlackListedMethods()

@mfn
Copy link
Contributor Author

mfn commented Feb 27, 2022

Yes, this approach also works but it has an inverse impact on the DX: I need to specify all methods I want to mock. In my case it's like 6 or 7.

With the setBlackListedMethods I just define which one we keep ignoring, in your suggestion I need to list all the methods I later use via shouldReceive.

Both work, but I'll stick with the variant using setBlackListedMethods as it requires no further "maintenance", should the test change.

Especially with Redis::class, this is super-hideous as any new method being called on it (and not being expected) will lead to a "Server gone away" error and then bug hunting is super-not-fun.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants