Unit testing Zend Framework Applications

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
Luke
The Ninja Space Mod
Posts: 6424
Joined: Fri Aug 05, 2005 1:53 pm
Location: Paradise, CA

Unit testing Zend Framework Applications

Post by Luke »

I was asking around on the #zftalk irc channel about unit testing zend framework applications and was told to check out this proposal: http://framework.zend.com/wiki/display/ ... astructure

Although I'm very excited that there is talk of including unit testing functionality, I'm a little disappointed with the methodology. If I understand correctly, you have to wait for the response object to be returned (with rendered view) before you can do any testing and then you use xpath / css selectors to verify that certain things were in the response. I have no interest in the actual output / response. All I want to know is whether or not the view received the correct variables. What it does with them after that is of no concern to me (at least not while Im testing my controllers). As long as the views get the right information, they can do whatever they want with them...

Am I understanding this correctly? Is my methodology correct?
User avatar
Luke
The Ninja Space Mod
Posts: 6424
Joined: Fri Aug 05, 2005 1:53 pm
Location: Paradise, CA

Re: Unit testing Zend Framework Applications

Post by Luke »

Once again Django does things exactly how I'd like them done... check out how easy and awesome this is: http://www.djangoproject.com/documentation/testing/

There are two unit testing modules built-in to python itself and Django has had built-in unit testing from the ground up. There is a client made specifically for unit testing that returns a django response object with access to what is called a context... which is where the view (or template as they call it) gets its variables.

Code: Select all

 from django.test import TestCase class SimpleTest(unittest.TestCase):    def setUp(self):        # Every test needs a client.        self.client = Client()     def test_details(self):        # Issue a GET request.        response = self.client.get('/customer/details/')         # Check that the respose is 200 OK.        self.failUnlessEqual(response.status_code, 200)         # Check that the rendered context contains 5 customers.        self.failUnlessEqual(len(response.context['customers']), 5) 
It's also got support for testing email, authentication, database calls, redirects (and basically any other http stuff) and a bunch of other stuff.

Who wants to help me write something comparable to this for the Zend Framework? :lol: :lol:
User avatar
Eran
DevNet Master
Posts: 3549
Joined: Fri Jan 18, 2008 12:36 am
Location: Israel, ME

Re: Unit testing Zend Framework Applications

Post by Eran »

Submit a framework proposal, maybe somebody will pick it up
User avatar
Luke
The Ninja Space Mod
Posts: 6424
Joined: Fri Aug 05, 2005 1:53 pm
Location: Paradise, CA

Re: Unit testing Zend Framework Applications

Post by Luke »

Problem is, to do something like this would require a pretty major overhaul of the mvc architecture. :(
User avatar
Luke
The Ninja Space Mod
Posts: 6424
Joined: Fri Aug 05, 2005 1:53 pm
Location: Paradise, CA

Re: Unit testing Zend Framework Applications

Post by Luke »

Hmm... where's Maugrim_The_Reaper on this one?? :(
User avatar
Maugrim_The_Reaper
DevNet Master
Posts: 2704
Joined: Tue Nov 02, 2004 5:43 am
Location: Ireland

Re: Unit testing Zend Framework Applications

Post by Maugrim_The_Reaper »

Maug is just overwhelmed with stuff ;). I can't check the forums daily for the moment, unfortunately...

If you read the proposal, you probably saw my comment on it and Matthew's response. The added support is technically for functional or acceptance testing, not unit testing per se. Common misconception that the proposal will increase no doubt, but unit testing assumes you can test in isolation whereas functional testing (which can use PHPUnit, Selenium, etc.) has no isolation - you test the entire request/dispatch/controller/view process from end to end.

So will this solve your unit testing needs? Probably not to extent needed for TDD (and certainly not BDD). Depends on how you do TDD. In my case, I write Models and Controllers and use extremely basic placeholder views - so it's almost pointless to me. My Views are not concrete during TDD, so functional testing would be disastrous - the moment my View changes to something permanent all my tests would immediately fail. Worse, my Views tend to go through iterations - so fail, fail, and fail again. It's a blackhole of test maintenance. Not to mention what happens when client requirements shift like sand!

You are almost right that it needs an MVC overhaul, so testing is layered far closer to the Controller. The problem is that you can't mock PHP's "new" keyword which is my biggest pain with Controller testing - one solution is to use minimal Dependency Injection (see Zend_Di which has a really light testing API for object/class replacement) so object instantiation in a Controller is abstracted and interceptable. Then tests can literally tell the DI container to instantiate a Mock in place of the original object ;). Not incredibly pretty, but PHP doesn't have Ruby's outlook of "new" being a class method to be overridden!

Then apply Mock Objects in place of the Request, objects instantiated in Actions, and Models and you get very close to the ideal. All you then need is a testing framework supporting a spot of automated setup/teardown of requests, and a short API to assertions.

From Matthew's comments on this proposal, and elsewhere, I gather it will be ZF 2.0 before something more invasive is remotely feasible.
User avatar
Luke
The Ninja Space Mod
Posts: 6424
Joined: Fri Aug 05, 2005 1:53 pm
Location: Paradise, CA

Re: Unit testing Zend Framework Applications

Post by Luke »

YAY! I'm glad you responded paddy! I did see your response and agreed with you completely. I have been doing a lot of research on the subject. I think that if I used a class for my bootstrap instead of a simple file, and if I replaced several of zend's components with my own extensions of them (off the top of my head I'd probably have to extend the front controller, request, response, view, and viewRenderer), I just might be able to test controllers how I've suggested. I'm actually putting together a document about zend's front controller / mvc components to get a better grasp on how things work (as well as teach a co-worker). Once I'm done with it I'm going to study, study, study and hopefully find a way to make the framework unit testable (at the application level) with as little extension as possible. If I could build a fake request, and return an extended response that gives access to the view(s) that its made up of, that just may be enough.

Code: Select all

class TestFooController extends Q_UnitTest_Controller_Action
{
    protected $_client;
    public function setUp() {
        $this->_client = new Q_UnitTest_Controller_Client;
    }
    public function testBarActionContainsBars() {
        $response = $this->_client->request("/foo/bar");
        $this->assertEqual($response->getCode(), 200);
        $this->assertEqual(count($response->getViewContext()->bars), 10);
    }
}
Of course there is going to be a lot more to it because in this case, I'd likely have to mock the database results and in many cases I'd have to mock the sending of an email, the creation / use of cache, and a plethora of other external (hard-to-test) stuff. In the case of the proposal I mentioned, none of these things would be possible.

Also, do you agree that the proposal solves the problem of testing the view / template rather than the controller?
User avatar
Maugrim_The_Reaper
DevNet Master
Posts: 2704
Joined: Tue Nov 02, 2004 5:43 am
Location: Ireland

Re: Unit testing Zend Framework Applications

Post by Maugrim_The_Reaper »

You can also take a peek at PHPSpec's subversion repository - before March's loss of focus I was starting to pound up the slope on applying BDD to ZF application development. But yet, the core requirement is a Boostrap Class where the preparation of the application environment is separated from the actual command to the Front Controller to dispatch something. The more separation the better really - even the PHPSpec code was a very early cutout. I can't remember if I even bothered to apply BDD on it since it was more a proof of concept to feel out the requirements.

If you want to know more about PHPSpec's ideal, the API I was aiming for was similar (can't be identical unless you force Dependency Injection) to rspec's.
Also, do you agree that the proposal solves the problem of testing the view / template rather than the controller?
Actually I'd say it's questionable ;). It's sufficient for acceptance or functional testing only (if that's what you meant then I readily agree) where you should run the entire application stack (request->controller/model->view->response). But even View testing needs something new. For example, unit tests are development tests - so the key question for a test might be to check a particular controller renders the correct template, the correct set of partials, sets a value in the right Placeholder, etc, rather then test against the output immediately.

I think that borders on pedantry though - it's really only useful if half way through development you still haven't a clue what the basic UI content should be. That is possible, but usually by then you'd have acceptance tests passing which are just about flexible enough you can alter the View quite widely without breaking them all so it should be a rarity.

I think that's probably the whole point - the proposal addresses functional testing only. Nothing else. If you restrict yourself to that view it's quite a good proposal for that one objective.
josh
DevNet Master
Posts: 4872
Joined: Wed Feb 11, 2004 3:23 pm
Location: Palm beach, Florida

Re: Unit testing Zend Framework Applications

Post by josh »

The Ninja Space Goat wrote: Who wants to help me write something comparable to this for the Zend Framework? :lol: :lol:
I would
The Ninja Space Goat wrote: I think that if I used a class for my bootstrap instead of a simple file
That's what I'm doing and its working well, bootstrap provides init() and run() methods, the bootstrap gets extended for testing and only init() is called, tests dispatch themselves.
The Ninja Space Goat wrote: if I replaced several of zend's components with my own extensions of them (off the top of my head I'd probably have to extend the front controller, request, response, view, and viewRenderer)
Wouldn't you just subclass the action controller and mock those other components?
The Ninja Space Goat wrote: I'm actually putting together a document about zend's front controller / mvc components to get a better grasp on how things work (as well as teach a co-worker). Once I'm done with it I'm going to study, study, study and hopefully find a way to make the framework unit testable (at the application level) with as little extension as possible. If I could build a fake request, and return an extended response that gives access to the view(s) that its made up of, that just may be enough.
Link me please to your article(s). I think an abstract factory for model instantiation is in order, no?
User avatar
Luke
The Ninja Space Mod
Posts: 6424
Joined: Fri Aug 05, 2005 1:53 pm
Location: Paradise, CA

Re: Unit testing Zend Framework Applications

Post by Luke »

Ah, one of many many projects I wanted to start and never got around to. One of these days I'd really love to get back to it, but I doubt it will be any time soon. Are you really interested in doing something like this?
josh
DevNet Master
Posts: 4872
Joined: Wed Feb 11, 2004 3:23 pm
Location: Palm beach, Florida

Re: Unit testing Zend Framework Applications

Post by josh »

If there was a need for it, I'm not really sure what exactly you would need to be able to test for a controller though
Post Reply