Archive for January, 2011

12Jan

So, I read this article a couple days ago: http://mark-story.com/posts/view/testing-cakephp-controllers-the-hard-way . As a result I started pulling my hair out. I decided that is too much work. Perhaps CakePHP 1.3 fixed some of the issues mentioned in that document, but no one has really documented anything. In any case, it took a few days of experimentation, but I got a nice template going. I see a ton of people interested in testing now a days, one thing to remember when you are starting out is that we are only testing controllers, and as such should only test what THIS controller is doing. Controllers in this sense only transfer data from one place to another, add a little bit of data, and really function as ¬†glue between models, views, components, utility classes etc. SOOO you should not be testing auth methods or if data is saved (thats what the tests for those classes are for. Furthermore, don’t test cake internal functions.

A couple more notes before the code…
– You need to set your debug level to 3
– This was a test straight from a CakeTestCase I started working on
– I tried a few ways to get access to auth/session data. This seemed to be the easiest way to do this. Simply login to your site with the user level that you’d like to test (or stay logged out). I tried to manually set the session data. I think cake doesn’t like that, and kills your session as a result.

<?php
/**
* @author parris
*/
class LrapackagesControllerTest extends CakeTestCase{
    /**
    * These should go somewhere more global
    */
    private function genRandomString() {
        $length = 10;
        $characters = '0123456789abcdefghijklmnopqrstuvwxyz';
        $string = '';
        for ($p = 0; $p < $length; $p++) {
            $string .= $characters[mt_rand(0, strlen($characters)-1)];
        }
        return $string;
    }

    private function genRandomDouble() {
        srand((double)microtime()*1000000);
        $randomnumber = rand(0,5);
        return $randomnumber;
    }

    function startCase(){
        echo "<h1>Starting LrapackagesController Test Case</h1>";
        $this->path = APP_PATH.'/lrabuilder/lrapackages/';
        $this->testPackage = array(
            'Lrapackage'=>array(
                'name'=>$this->genRandomString(),
                'part_number'=>$this->genRandomString(),
                'version'=>$this->genRandomDouble()
            ));
    }

    function endCase(){
        echo "<h1>Ending LrapackagesController Test Case</h1>";
    }

    function startTest($method){
        echo '<h3>Starting method '.$method.'</h3>';
    }

    function endTest($method){
        echo '<hr/>';
    }

    function testAdd(){
		$result = $this->testAction($this->path.'add',array('data'=>$this->testPackage,'method'=>'post','return'=>'vars'));
		if($_SESSION['Auth']['User']['role_id']==1 || $_SESSION['Auth']['User']['role_id']==2)
		  $this->tAddLoggedInUser($result['cakeDebug']->data['Lrapackage']);
		else
		  tAddPublicUser($result);
	}

    function tAddLoggedInUser($data){
        $this->assertEqual($data['name'],$this->testPackage['Lrapackage']['name']);
        $this->assertEqual($data['part_number'],$this->testPackage['Lrapackage']['part_number']);
        //I would assertWithinMargin, but since the data needs to be identical, I don't need that.
        $this->assertEqual($data['version'],$this->testPackage['Lrapackage']['version']);
        //1000 is selected arbitrarily, but I dont care about real accuracy here.
        $this->assertWithinMargin(strtotime($data['created']),strtotime(date('Y-m-d H:i:s')),1000);
        $this->assertEqual($data['user_id'],$_SESSION['Auth']['User']['id']);
    }

    function tAddPublicUser(){
    	//echo($result); the only bad thing about this method is that you need to decide what the return var is before you
    	//have the session info... however, assuming you have properly setup your acl you shouldn't even need this test...
        //let the acl tests confirm that logged out users dont have access to logged in areas!!
    }

    function testIndex(){
        $result = $this->testAction($this->path.'index');
        //debug($result); this results in an overwhelming amount of data, be selective of the output!!
    }
}

Questions?

Go forth and unit test :)!

Some useful docs:

http://simpletest.org/api/SimpleTest/

http://simpletest.org/api/SimpleTest/Extensions/PHPUnit_TestCase.html

http://simpletest.org/api/SimpleTest/UnitTester/UnitTestCase.htm

http://book.cakephp.org/view/1210/Testing-controllers

Share