Controller testing in CakePHP
Posted on 24/8/06 by Felix Geisendörfer
Deprecated post
The authors of this post have marked it as deprecated. This means the information displayed is most likely outdated, inaccurate, boring or a combination of all three.
Policy: We never delete deprecated posts, but they are not listed in our categories or show up in the search anymore.
Comments: You can continue to leave comments on this post, but please consult Google or our search first if you want to get an answer ; ).
Besides making crazy plans about becoming a pro blogger, redesigning ThinkingPHP and coding on some personal projects for the last couple of days, I've actually found out some more interesting stuff regarding testing in CakePHP as well.
My first idea was to do unit testing on Controllers. I made a little comment about it here and uploaded some of my experimental code for that. In the beginning it looked very promising. I was able to mock Models & Components and add them to the Controller. But the deeper I got into it, the more I realized:
Unit Testing with Controllers is insane
When I started I liked the idea of mocking all the Models & Components, and have them act in certain ways to see how the controller reacts. I still think it would be nice to have, ... but I found that it's not practical at all. When you have a controller with just one Model and one Component, you already have a lot of overhead managing this two mocks, now imagine several bigger Controllers with several Models & Components. You would end up writing 4-5x as much code for unit tests as you would actually write for you application. That's the point for me where "theory about testing" has to go and agility has to kick in.
Looking over at railsland (*sigh*), I saw that them taking a different approach. Instead of testing the Controller as a unit, they would actually dispatch an url and then perform the tests on the most important things manipulated by the controller: assigns, cookies, sessions & flash. They also have a nice set of XML parsing toys to analyze the view output. That way you can perform your testing in a much overhead-reduced & natural manner. But of course it comes at the prices of testing a coupled system instead of a single unit. But then again, it's very agile and should provide reasonable tests to monitor the health of your application so you can easily refactor.
Bringing it to the world of CakePHP
For the last couple of days I've been puzzled by the question of how this could work within CakePHP. The problem was to dispatch an url and get access to the instance of the Controller afterwards. About an hour ago I had an idea: What would happen if I would write an extended Dispatcher and steal the instance from there? It took me a couple minutes until I realized that this is probably a very clean & easy approach and started to write some code. So far it worked out great. Using my new CakePHP bootstraping method that I presented a couple days ago, I was able to write test cases like this:
{
function test_index()
{
$response = $this->get('/posts/index');
$vars = $this->controllerVars;
$this->assertTrue(is_array($vars['posts']), 'Posts array is set');
}
}
If you are courious, that's how my TestDispatcher looked like, but keep in mind that there is some more code in the ControllerTest class which calls the TestDispatcher (and is set as a reference in $TestCase) to make everything run smoothly:
{
var $TestCase = null;
function dispatch($url, $additionalParams=array())
{
$additionalParams['return'] = 1;
return parent::dispatch($url, $additionalParams);
}
function _invoke (&$controller, $params, $missingAction = false)
{
$return = parent::_invoke($controller, $params, $missingAction);
$this->TestCase->Controller =& $controller;
return $return;
}
function cakeError($method, $messages)
{
$this->TestCase->cakeError = $method;
}
}
Where to go?
The next logical step for me is to refactor the testing code I use right now and add a couple of other functions to it. Once I'm done with this, I'll upload it as a PoC on this blog and everybody who's intersted is free to try it out. Depending on the feedback from you guys and the response of the people working on the new offical test suite, I'll try to bring it into a real test suite that we can use for testing our CakePHP apps in future.
--Felix Geisendörfer aka the_undefined
PS: I think it's still possible to mock single Models & Components by overwriting their instances in the Controller in the TestDispatcher::_invoke() function.
You can skip to the end and add a comment.
Hey Christian,
the truth is that CakePHP's testing suite is not suitable for testing your entire application yet. You can do some simple tests with Models but that's about it. Both, me and dhofstet are working on a testsuite that allows you to test controllers and the rest of the application as well. While his is based of the official testsuite, I started mine from scratch since I want to do some things different. However, at some point in the next weeks you'll see release alongside with tutorials for most likely both testsuites and I guess the users will decide which test style they prefer. Meanwhile you should not try to do TDD since you'll be overwelmed with the complexity of a new framework, simpletest and the integration of both which isn't completly done yet. Just give it some time and go on with the normal route ; ).
Thanks for the reply.
Yeah well, I think there's no option... But I'd like to see articles spread around the community which cover good coding practices when using cake. I mean, if there's no real TDD possible, one should consider another method to not make the programming a pain. I'd love to write articles, but I still lack cake-experience.
Hi Christian,
My work on the CakeTaster testsuite has a pretty high priority. I think the first PoC for early adopters will be released soon, so don't give up on it quite yet ; ).
One thing it'll also come with is a neat little interface, here is an early screenshot in case you care:
http://img291.imageshack.us/img291/5674/caketasterfr1.png
And once you get some more experience with CakePHP and my new blog is online, I'll consider the option of having other people contribute articles, etc., so if you would be interested in that, let me know.
Hey, Felix.
Any update on getting your ControllerTest up as a PoC? We're in the throes of some relatively involved controller testing right now, and it sounds like your setup could help us a ton. Thanks!
Mike
shaver: Well, hmm seems like I never got around to release a PoC and started to work on a real solution to the problem instead ; ). But it's all good - I'm close to release an alpha version of the resulting testsuite called caketaster and it will be uploaded on here soon ; ).
We're currently working from a modified version of a cakephp.org/pastes thing you put up some time ago, so please don't feel compelled to polish it on my account! :)
Looking forward to seeing CakeTester! Thanks again,
Mike
Great stuff,
Did you ever get any further with this? There seems to be some momentum behind testing in Cake, it'd be great to see this included.
matt
matt: I finally published the PoC at some point last year: http://www.thinkingphp.org/2006/11/16/release-early-release-often-caketaster/ but have not worked on it since then. When my time allows it I will try to make a point for integrating similar testing capabilities into the cake test suite natively.
This post is too old. We do not allow comments here anymore in order to fight spam. If you have real feedback or questions for the post, please contact us.
Sounds promising! I wanted to try TDD with Cake, but the documentation was near to non-existant, the wiki example didn't really help me out as well.
The problem for me, someone new to TDD and TDD + Cake (or RAD Frameworks in general) it's not easy to figure out what exactly I have to do in the test cases.
I go to /my_new_application/app/tests/app/controllers/blogpost.test.php and what I think about first is: how am I supposed to use the real controller or the blogpost model in here? How do I get the data I want, so I can test them for real?
Is it possible to test my whole application? Like fetching user data out of sessions or cookies or writing them after logging in? Am I supposed to use SimpleTests built in "browser" classes to do the testing?
The more I think about it, the more I just go nuts. I can't join the IRC because my Wireless LAN breaks the connection (same with ICQ) due to a very, VERY bad signal here and the internet has nothing left for a "TDD+Cake" beginner like me. Should I use Rails to get used to TDD in RAD Frameworks and then copy the techniques to Cake? I don't think that this really makes sense.
In C# I first tried TDD. It was a simple Debug.Assert(someVar, someValue); and everything went fine. I was even able to enhance the Assert output window, created some debugging classes myself etc., but in Cake I'm supposed to use something like "/my_new_application/app/tests/app/controllers/blogpost.test.php" without any access to my controller, my model or anything else?!
OK, C# will "exclude" the Debug stuff in final release of the application whilst PHP can't, but hey, what am I about to do THEN?
I think that's everything I have to say about my first steps with Cake and TDD. Or my first attempts of making my first steps with Cake and TDD. I mean, all I have is something like testing the Inflector class which has absolutely NOTHING to do with my very own application.
Should I applause now?