mock service in DI container

jz
Member | 1
+
0
-

Hi,

I'm writing integration tests for Nette app and I'd like to have an easy way to inject a mocked service/method into the DI container for specific test. I'm able to do it as you can see the code bellow. It is working for simple cases or only if I'm running just one test.

The problem is, that some services (created by previous tests) could hold the service as a private property (coming from the constructor). I'd need to inject the mock in all services dependent on the service I'd like to mock (or at least to force to recreate it again with mock as dependency).

Do you know how could I list all services which are dependent on specified service?

Regards

Jan

abstract class IntegrationTestCaseBase {
    protected Nette\DI\Container $diContainer;

// ....

    /**
     * @param class-string $diServiceType
     * @param mixed        $return
     *
     * EXPERIMENTAL! other services dependent on this service are holding the original service!
     */
    public function doubleDIServiceMethod(string $diServiceType, string $methodName, $return): void
    {
        $mock = $this->getMockForDIService($diServiceType);
        /** @var \Mockery\ExpectationInterface $exp */
        $exp = $mock->shouldReceive($methodName);
        $exp->andReturn($return);
    }

    /**
     * @param class-string $diServiceType
     * @return \Mockery\MockInterface|\Mockery\LegacyMockInterface
     */
    public function getMockForDIService(string $diServiceType)
    {
        $wiredClassName = $this->getWiredClassName($diServiceType);
        if (!isset($this->originalServiceList[$wiredClassName])) {
            $this->originalServiceList[$wiredClassName] = $this->diContainer->getService($wiredClassName);
        }
        if (!isset($this->mockedServiceList[$diServiceType])) {
            $this->mockedServiceList[$diServiceType] = Mockery::mock($this->originalServiceList[$wiredClassName]);
        }
        $this->diContainer->removeService($wiredClassName);
        $this->diContainer->addService($wiredClassName, $this->mockedServiceList[$diServiceType]);
        return $this->mockedServiceList[$diServiceType];
    }


    /**
     * @param class-string $diServiceType
     */
    private function getWiredClassName(string $diServiceType): string
    {
        if (!isset($this->wiredClassNameList[$diServiceType])) {
            $this->wiredClassNameList[$diServiceType] = $this->diContainer->findAutowired($diServiceType)[0];
        }
        return $this->wiredClassNameList[$diServiceType];
    }

    private function restoreOriginalServicesInDIContainer(): void
    {
        foreach ($this->originalServiceList as $wiredClassName => $originalService) {
            $this->diContainer->removeService($wiredClassName);
            $this->diContainer->addService($wiredClassName, $originalService);
        }
    }
}
David Grudl
Nette Core | 7780
+
0
-

Nette DI can't return this.