Search code examples
phpunit-testingtypo3typo3-9.x

How to mock the object manager in Typo3 unit-tests


I'm writing some unit-tests for a typo3 v9.5 extension, and I can not figure how to properly mock objects when the under-test function is instanciating them using GeneralUtility::makeInstance(ObjectManager::class)->get(...)

If possible, I'd like to use the prophecy framework, but that's not mandatory.

For example, if the function under-test is like:

public function getRootline($pageUid) {
    $pageService = GeneralUtility::makeInstance(ObjectManager::class)->get(PageService::class);
    return $pageService->getRootLine($pageUid);
}

How could I test this and mock the Pageservice class?

I tried different variations of this solution:

$pageServiceProphecy = $this->prophesize(PageService::class);
$pageServiceProphecy->getRootLine($pageUid)->shouldBeCalled()->willReturn($myRootLine);

$omProphecy = $this->prophesize(ObjectManager::class);
$omProphecy->get(PageService::class)->shouldBeCalled()->willReturn($pageServiceProphecy);

GeneralUtility::setSingletonInstance(ObjectManager::class, $omProphecy->reveal());

But I get various cryptic errors every time. The given version raises the error:

TYPO3\CMS\Core\Cache\Exception\NoSuchCacheException: A cache with identifier "cache_runtime" does not exist.

Solution

  • Actually you should make use of dependency injection in the class which exposes the getRootline() API, then you can have the PageService injected this way:

    final class MyCustomClass {
        private PageService $pageService;
    
        public function __construct(PageService $pageService)
        {
            $this->pageService = $pageService;
        }
    
        public function getRootline(int $pageUid)
        {
            return $this->pageService->getRootLine($pageUid);
        }
    }
    

    While testing you can inject a mock instead:

    $pageService = $this->prophesize(PageService::class);
    $myCustomObject = new MyCustomClass($pageService->reveal());