Testing ZF Controllers and Model interactions

Not for 'how-to' coding questions but PHP theory instead, this forum is here for those of us who wish to learn about design aspects of programming with PHP.

Moderator: General Moderators

Post Reply
User avatar
Maugrim_The_Reaper
DevNet Master
Posts: 2704
Joined: Tue Nov 02, 2004 5:43 am
Location: Ireland

Testing ZF Controllers and Model interactions

Post by Maugrim_The_Reaper »

Alright so here's the summary version. I'm looking into substantially improving how I apply TDD/BDD to Zend Framework applications. At the moment my current PHPUnit test suites are frankly horrible. Luckily these are small projects.

The problem emerges in a few levels.

1. The Zend Framework has no built-in testing shortcuts
2. Test setup is inordinately long, even with some code refactoring to a Test subclass
3. PHPUnit doesn't have Mock Object support at a sufficient level (so stubs/mocks are hand coded more often than not)
4. It's a bit hard to mock objects directly instantiated in a ZF Controller
5. The suites are really a soup of integration tests.

My question here is to request opinions on how best to solve no. 4 (more a programming problem, than a strict testing one). I have been considering using something akin to a Registry which is handled independently of the Zend Framework. Instead of storing objects, it would store or locate/instantiate classes. As a quickie example of this thought, consider a theoretical PHPSpec example with an even more theoretical Zend Framework integration plugin:

Code: Select all

<?php

// __ControllerName convention
class Describe__IndexController
{

    /**
     * In the opening setup, I create a Mocked class for a real
     * Article model class. replaceModel() is a plugin method attached
     * to a PHPSpec_Plugin_ZendFramework class which interfaces to a
     * framework specific Zend_Action_Controller_Helper_ModelRegistry
     * class which is responsible for loading/managing Model objects.
     * Probably more accurately a Service Locator.
     */

    public function before() 
    {
        $this->article = phpmock('Article');
        $this->replaceModel('Article', $this->article);
    }

    /**
     * The replaced Article object is a Mock. Interaction with it within
     * the targeted controller should meet the specificed expectations.
     * post() is another Plugin method which dispatches a POST request to
     * the selected Controller action (the first parameter, create).
     *
     * For completeness sake, it's assumed there is a Response object
     * available, but it is also assumed a View is not rendered unless the
     * before() setup method configured to allow View rendering into a 
     * Response. Don't worry about this detail...;)
     */

    public function itShouldSaveNewArticleFromPostRequestToCreateAction() 
    {
        $this->article->shouldSet('title')->with('I Am Article Title');
        $this->article->shouldReceive('save')->once();
        $this->post('create', array('title'=>'I Am Article Title'));

        // because PHPSpec does not yet auto-validate PHPMocks
        $this->spec($this->article->verify())->should->beTrue();

        // Response expectations if warranted
        $this->response()->should->beSuccess(); // i.e. status 200
    }
} 
Finally, a possible implementation ignoring all security concerns! We'll assume Article is a simple Model class. We'll also assume that PHPSpec Plugin has disabled auto-rendering of a View other than that we explicitly assign to the Response object.

Code: Select all

class IndexController extends Zend_Controller_Action
{

    public function createAction()
    {
        $article = $this->loadModel('Article');
        $article->title = $_POST['title'];
        $article->save();
        $this->getResponse()->setBody('Article Saved');
    }

} 
Not sure what to go with here for substituting Models. Suggestions?
User avatar
Christopher
Site Administrator
Posts: 13596
Joined: Wed Aug 25, 2004 7:54 pm
Location: New York, NY, US

Re: Testing ZF Controllers and Model interactions

Post by Christopher »

I really can't think of anything short of implementing your own Zend_Controller_Action and putting it first in the include search path (before the real one). You are then chasing releases to update your own code. Zend pushed too much functionality into the Action Controller in my opinion.
(#10850)
User avatar
Maugrim_The_Reaper
DevNet Master
Posts: 2704
Joined: Tue Nov 02, 2004 5:43 am
Location: Ireland

Re: Testing ZF Controllers and Model interactions

Post by Maugrim_The_Reaper »

I'm thinking of proposing a static Factory style class. Something using an optional registry to facilitate replacements. Would require Controller code actually use it (as opposed to "new Something" everywhere).

Blogged up some semblance of a plan of approach:
http://blog.astrumfutura.com/archives/3 ... amble.html
User avatar
Christopher
Site Administrator
Posts: 13596
Joined: Wed Aug 25, 2004 7:54 pm
Location: New York, NY, US

Re: Testing ZF Controllers and Model interactions

Post by Christopher »

Yikes! ;)
(#10850)
User avatar
Maugrim_The_Reaper
DevNet Master
Posts: 2704
Joined: Tue Nov 02, 2004 5:43 am
Location: Ireland

Re: Testing ZF Controllers and Model interactions

Post by Maugrim_The_Reaper »

Was that a good yikes! or a bad yikes!? ;)
Post Reply