Thursday, November 19, 2009

More questions on controllers testing

Sune wrote to me yesterday with some questions about testing Zend Framework controllers and proper dependency injection, which to me is a fundamental practice in object-oriented programming. I have already responded to similar mails in the past and this seems to be an hot topic nowadays, so as always I think other readers can benefit from this discussion and I'm sharing it here.
Because of you I am trying to move my software to use factories and dependency injection, also removing
singletons and Zend_Registry usage in controllers. But I am a bit confused, what is the right way to do this.
My plan is to bootstrap the main factory in the bootstrapper, and then use
$this->getInvokeArg('bootstrap')->getResource('factory') in controllers. Is this good practice?
Summarizing, the best thing would be creating the controller by yourself (or having its creation configured someway), but it can be an overkill to set up a similar approach on a Zend Framework application, since it requires a third-party DI container and controllers should always be thin.
Thin controllers means we probably want only to perform integration testing on them with Zend_Test, and not real unit testing as there is not much logic to exercise.
Since we cannot create in the bootstrap all the collaborators that could be possibly needed (we want to lazy-load collaborators that may not be referenced), your approach is similar to a Guice provider and I think it is very valid. In integration testing you should then use a different factory or configure this one to provide some fake components when the real ones are not applicable. For instance, a mailing service object ca be replaced with a fake implementation that records all the sent mail and lets you assert on them.
And in conjunction with that. Would it be good practice to inject a Zend_Config object into the factory?
Some models requires options from the config file, smtp username etc. and the factory would need those information to create the models.
Of course. It's up to you how to organize the config object, and you can and should change part of it in the testing environment. The power of DI containers is that during configuration you can specify not only scalars like database connection strings, but also different classes and implementation for the collaborators you inject.

1 comment:

Sune Pedersen said...

Thanks for taking the time to answer my questions, it gives me comfort that I am on the right path ;)