While writing tests for the new Feedback plugin, I learned a few things about cake's testing framework and PHPUnit.
Below are some general guidelines, but first, if you haven't done so, please go ahead and read The Cookbook on testing controllers because this is not the all-encompassing tutorial you may be looking for.
First of all, make sure your test class extends
ControllerTestCase, not the plain-old
CakeTestCase. This gives you access to the awesome
generate() method, which will mock your controller methods when necessary, but more importantly, it will mock the week out of the surrounding stuff like components and models.
$this->generate ( 'Feedback.Ratings', array ( 'models' => array ( 'Feedback.Rating' => array('create'), 'Article' => array('read'), ), 'components' => array ( 'Feedback.Ratings', ), ) );
This is great stuff because you can completely isolate your controller and make real unit tests.
However, be carefull about one thing: if you mock only a few methods of your object, the rest of the methods are the original methods. In the example above, I've mocked the method
Article::find() (for example) is the real find method, and it will attempt to query your database.
When things start to get freaky, make sure you're not calling a non-mocked method when you did not intend to do so.
Next, you obviously test your controller by calling
$result = $this->testAction ( '/feedback/ratings/add/Arse/1', array ( 'data' => $data, 'return' => 'headers', 'method' => 'post', ) );
There is, however, a gotcha when doing this in combination with
If you try to call
testAction() several times in a row in a single test action, you're going to have a bad time. Why? Because testAction will try to re-mock your controller, provided that
autoMock property is true (and by default, it is).
While this is a good thing, testAction is not the brightest kid in the class. It will re-mock everything, but it will not do it the way you did, with your settings. In other words, what you wanted to be a mock object may not be a mock object at all. Your expects() will fail on things like CakeRequest methods, and you'll have no idea why. This means it will pretty much mess up the test badly, and your hair will fall out while you try to find out what went wrong (not that you have any hair now, right?).
In other words:
don't use testAction() more than once per test
Of course, this is a good advice regardless of this "feature", because it is a good practise to test only one thing per test, and different calls to testAction are not testing the same thing by definition.
Last but not least, you may have trouble finding out how to simulate things like AJAX requests, client IP address etc.
Fortunately, there's a way to do that too; you can simply do this in your
$_SERVER['HTTP_X_REQUESTED_WITH'] = 'XMLHttpRequest'; $_SERVER['REMOTE_ADDR'] = '127.0.0.1';
Et voilà! Hackish? Yes. But it works, and that's good enough for now.