0

PHP 8.1.1 / Laravel 9

I had Config:get('keycloak.employees_group_id') in my task, and Config::shouldReceive('get')->with('keycloak.employees_group_id')->andReturn('fake-id') in my test which worked NP.

Then I wanted to use DI (dependency injection) approach and my task changed to the following.

Task

class FetchGroupMembers implements TaskHandler
{
    public function __construct(
        private Config $config,
        ...
    ) {}

    public function handle(ExternalTask $task): array
    {
        $employeesGroupId = $this->config->get('keycloak.employees_group_id');

        ...
    }
}

Test

How do I test this now?

I have tried the following, but none of them work.

class FetchGroupMembersTest extends TestCase
{
    private MockInterface|Config $config;
    ...

    public function setUp(): void
    {
        parent::setUp();

        // Option 1
        $this->config = Mockery::mock(Config::class);
        // Option 2
        $this->config = Mockery::mock(Config::class, function (MockInterface $mock) {
            $mock
                ->shouldReceive('get')
                ->with('keycloak.employees_group_id')
                ->andReturn('fake-id')
        });
        // Option 3
        $this->config = $this->mock(Config::class)
        // Option 4
        $this->config = $this->mock('alias:' . Config::class);
        ...
    }

    public function testFiltersOutUsersWithoutGeckoId(): void
    {
        $employeesGroupId = 'fake-id';
        ...

        // Options 1, 3, 4
        $this->config
            ->shouldReceive('get')
            ->with('keycloak.employees_group_id')
            ->once()
            ->andReturn($employeesGroupId);
        ...

        $fetchGroupMembersHandler = new FetchGroupMembers(
            $this->config,
            ...
        );
        $variables = $fetchGroupMembersHandler->handle($this->task);
        ...
    }
}
s3c
  • 1,481
  • 19
  • 28
  • `Config` is a facade so you can directly use `Config::shouldReceive...`. You shouldn't mock facades themselves. More details in the [docs](https://laravel.com/docs/9.x/mocking#mocking-facades) – apokryfos Apr 16 '22 at 13:13
  • I had just that, as you can read in the first paragraph of this Q. Then I had to change it because we don't want to have hidden dependencies in our services. Now I'm thinking it'd probably be best not to inject the facade at all, and should instead just put the `private string $employeesGroupId` in the constructor. – s3c Apr 17 '22 at 03:04
  • The other way to mock a facade is to actually mock the singleton that the facade is in front of (for lack of better explanation). However since this is a built-in facade I don't think it's a good idea to go through this approach since that means looking into the source code and updating if at any point in the future that changes. For example right now the facade accessor for the `Config` facade may be the `'config'` binding but in the future it may become the class that is behind the `'config'` binding – apokryfos Apr 17 '22 at 05:26

0 Answers0