phpunit-testingzend-framework2servicemanager

ServiceManager can't find classes by full namespace when testing with phpunit


I'm retrieving instances from the ServiceManager by their full class names in some cases, for example:

$someThing = $serviceManager->get('MyModule\Some\Nice\Lib\SomeThing');

This works pretty well for HTTP MVC requests, however, when using phpunit, the ServiceManager can't find it. (It throws a Zend\ServiceManager\Exception\ServiceNotFoundException exception with message "Zend\ServiceManager\ServiceManager::get was unable to fetch or create an instance for ...")

I'm using the default testing bootstrap example from the docs and I experience this issue in two different projects on different mashines, so I guess this is a general problem.

My first guess was that it has something to do with MVC or application, becuase this is most likely the only real difference between testing and http. I even dumped the SM instances in both modes and compared them with each other, looked through the sources and searched the web.

Unfortunately, I can't paste any code due to my labor contract. However, as I said, I think this is a general problem so you should be able to easily reproduce it.

Does anybody know what is causing this issue and how to solve it?


Solution

  • I managed to locate the problem.

    When you create an instance with its full class name using ServiceManager, it won't in fact be able to create it by default. However, if possible, it delegates the task to the abstract factories that are attached to it.

    Now, when you create a Di instance using the DiFactory, the factory registers a DiAbstractServiceFactory to SM. And, you guess it, this abstract factory is able to instantiate classes by their full class names.

    I've rarely used Di in this project (because I didn't really feel comfortable with it and used it wrong in the beginning; I know better now), which is why the only point where I instantiate Di is inside the onBootstrap() method of a module. This is fine in MVC context, however, as onBootstrap() is an HTTP MVC event handler, it won't be invoked in my testing application. Thus, no Di is instaniated at any time, thus, ServiceManager hasn't got the DiAbstractServiceFactory attached to it, thus it can't delegate the get() call, thus it fails to instantiate classes by their full class names.

    It's as simple as that! :-)

    The obvious solution: Create a Di instance inside the testing application.