Anatomy of a CakePHP Test Case
Aug 23 2008
With all the talk of testing going on, I thought it would be good to look at how tests work and what is makes them tick. SimpleTest handles the bulk of test case execution, however, there are a few CakePHP specifics that are not part of a normal SimpleTest::UnitTestCase. By using CakeTestCase as the base class for your unit tests you get a few extra features such as Fixtures, Tag Assertion, and Controller Action testing, all of which make your tests more effective and easy to use.
Fixtures
Fixtures give you a way to insulate and isolate your tests, they allow for the creation of known data. By having known data you isolate your application’s test suite from the changes made to your application’s data. Fixtures are generated automatically if you bake your models too, making them easy to pick up and use.
Using fixtures in your tests
Show Plain Text- <?php
- class MyTestCase extends CakeTestCase {
- }
- ?>
The above would prepare the post and comment fixture for each of your test cases. The tables are truncated and re-inserted between each test case method as well, so you don’t have to worry about data bleeding through on your tests.
Tag Assertion
Tag Assertion is most helpful in regards to verifying helper output, or any generated HTML. Tag assertions streamline testing HTML output by replacing long complicated regular expressions with easier to understand arrays.
Show Plain Text- <?php
- $result = '<a href="/test.html">My link</a>';
- 'My link',
- '/a'
- );
- $this->assertTags($pattern, $result);
- 'Email',
- '/label',
- '/div'
- );
- $this->assertTags($result, $expected);
- ?>
The above gives a simple example of what can be done with assertTags(). Basically any snippet of HTML can be checked with assertTags(). The attributes in your pattern do not need to be in the same order as your text. However, all the text needs to case match the text you are checking. Also keep in mind that assertTags() will only work if your output’s attributes are double quoted, single quotes are not supported at this time.
Controller Action tests
Unit testing works fantastically for checking individual methods, and groups of methods. However, testing an entire request to your application is tricky. It can be a complicated process, setting the request parameters, constructing all the necessary classes, calling the action, and finally capturing the view output. This sounds like a lot of work and it is, enter testAction(). testAction() encapsulates a request and gives you a few options for checking the output. The return of testAction() can be View variables set by the controller, the return of the controller action, the bare rendered view, or an entire page. Furthermore, you can employ the same fixtures used in your model tests, or import existing table data into your test fixtures.
- <?php
- ?>
There are several other options and configurations as well, but it is enough to fill up a separate post.
Test Method Execution order
Now that we’ve covered some of the functional differences CakeTestCase offers from UnitTestCase, we’ll take a look at what methods fire and when. CakeTestCase adds several methods to UnitTest and they are fired at specific times. By knowing when they run you can leverage them more effectively in your tests.
- start Initializes the test, fixtures are created here.
- startCase signals the beginning of a the test case.
- testCaseMethods All of your test case methods fire here.
- endCase signals the end of a test case.
- end the end of the test, fixtures tables are dropped.
Furthermore, each and every of the above methods has before() and setUp() called before it. tearDown() and after() are called after each test. Start and After refresh your fixtures by inserting and truncating the tables and should only be overloaded if you need to change how the fixtures work. Both setUp() and tearDown() can be used to reset the state of your test case in between test case methods.
Search
Categories
Recent Posts
- Using bindModel to get to deep relations
- New home, new sideproject
- Using bitmasks to indicate status
- AclExtras Shell
- Getting a new Oven, Migrating from CakePHP 1.1 to 1.2
- Code Completion for CakePHP in Eclipse
- CakePHP RC3 released and CakePHP 1.1 new release
- Book Review: CakePHP Application Development
- Providing Contextual Form Help with Mootools
- Creating gracefully degrading javascript and enabling progressive enhancement
Comments
Jetpac on 20/10/08
Hey Mark,
can you give an idea of how to test eg a controller::delete() method that has no view but just redirects to controller::referer() ?
controller::redirect() redirects out of the test but if i subclass the controller and avoid the redirect i get a missing view error.
Any tips would be greatly appreciated – thanks!
mark story 3 weeks, 5 days ago
JetPac: I would make
TestPostsControllerclass and override the redirect() method to set a property to the last redirected url. When subclassing make sure that you define viewPath to the old controller’s path, if you don’t you’ll get that missing view error. You can see examples of this in the core tests.Have Something to say?