Jul
2
2012

Using PHPUnit in Yii Framework

As known, phpunit is a unit testing tool for php and as it seems very successful. Btw, yii framework add some new classes at the top of the phpunit to make easy to write testing codes. In this post, firstly I will try to tell some generic info about phpunit testing. After that try to tell which codes we can test and how in a yii webapp. I assume phpunit is installed and working correctly, if not please look at the phpunit website.

Testing is the indispensable part of software developing. Testing can be made by manual or automatic. Manual testing is very time consuming and boring. However  automatic testing is  more fun and a key point for software quality.  For instance ,when new  things are added to code, you click a button or run all test codes and produces the testing report which tells everything is still ok or not. After this brief introduction, let’s move the coding part.

What unit testing is and naming conventions.
Unit tests can be written generally for the functions to see if it is working correctly. For instance suppose that we have a class with name “Users” and we have functions in “Users” class. Then, by convention we write a new class with name “UsersTest” in a “UsersTest.php” file to test the functions in “Users” class. Also “Test” suffix is important because phpunit find the testing codes’ files by looking theirs suffixes. In addition, there is another convention in function naming. For example, assume that we have “saveUser” function in “Users” class, we add a “testSaveUser” function to “UsersTest” class to test “saveUser” function in “Users” class. At this time, “test” prefix is important because phpunit finds the functions in a class whose names starts with “test” to run them.

Fixtures, setup(), tearDown()
By the way, in testing we sometimes need a special state to make the test run. Let me give an example, if I am testing the changing the password of a user then I need a user saved in a table in my database also probably i should know the current password of that user to change it with the new one so the state, to run the test code for changing password, is the fixture of the test.

phpunit provides a standard way to prepare the environment before the test run with “setup()” function and release or delete the resource after the test with “tearDown()” function. Yeah, if you write “setup()” and “tearDown()” function. Before each testing functions(testSaveUser, testChangePassword, etc.) run, “setup()” function is called and after each testing functions, “tearDown()” function is called.

Writing test codes for Yii WebApp
As known, yii is a MVC(Model View Controller) framework so the logic(controller), data(model) and views are separated from each other. Simple functions, for instance saving data for the user, changing password of the user or simple update functions for a record in the database, should take place in model classes. Then we can easily write test codes for these functions. I think these simple functions is very important

In a yii webapp, there is a “protected/tests” folder which contains fixtures, unit, functional folders and bootstrap.php, phpunit.xml and WebTestCase.php files. bootstrap.php in the first file that runs first. phpunit.xml is the configuration file of phpunit. WebTestCase is the base class for functional testcases. unit folder is the folder which contains unit testing files. functions folder is for functional testing files and lastly fixtures is for fixture files. Now, let’s pass the coding part.

Assume that we have a “saveUser($email, $password, $name)” function which adds a new row to table in “Users” model class. Here is a sample code for testing this “saveUser($email, $password, $name)” function.

File path: protected/tests/unit/UsersTest.php
———————————————————————
require_once(“bootstrap.php”);

class UsersTest extends CDbTestCase {

public function testSaveUser() {
//preparing variables
$email = “test@test.com”;
$password = “1231231″;
$realname = “test”;

//calling saveUser function in Users model, it should return true
// if it returns true below assertion passes, otherwise failes.
$this->assertTrue(Users::model()->saveUser($email, $password, $realname));

// now getting the all rows with email test@test.com
// findAll function returns all rows in an array mathes the criteria

$rows = Users::model()->findAll(“email=:email”, array(“:email”=>$email));

//check that it should be one element in rows array

$this->assertEquals(count($rows), 1);
//check that email, password and realname is saved correctly
$this->assertEquals($rows[0]->email, $email);
$this->assertEquals($rows[0]->password, $password);
$this->assertEquals($rows[0]->realname, $realname);

try {
//try to register same e-mail address, it should throw exception and should
// skip the below assertion and must execute the catch block.
Users::model()->saveUser($email, “1232424″, “test”);
$this->assertTrue(false);
}
catch (CDbException $exp){
$this->assertTrue(true);
}

}

public function testMissingParameters() {

//try to register with missing parameters
$this->assertFalse(Users::model()->saveUser(“dene@deneme.com”, “”, “”));
$this->assertFalse(Users::model()->saveUser(“”, “1232424″, “”));
$this->assertFalse(Users::model()->saveUser(“”, “”, “”));
$this->assertFalse(Users::model()->saveUser(“dene@deneme.com”,

“1232424″, “”));

$this->assertFalse(Users::model()->saveUser(“”, “1232424″,

“deneme traceper”));

$this->assertFalse(Users::model()->saveUser(“dene@deneme.com”, “”,

“deneme traceper”));

$this->assertFalse(Users::model()->saveUser(“”, “”, “deneme traceper”));

}

public function testWrongFormattedEmail(){

//try to register with a wrong formatted email address
$this->assertFalse(Users::model()->saveUser(“denedeneme.com”, “1232424″,

“deneme traceper”));

}

}

we can run this code above with the below command.

// you should be in protected/tests directory
phpunit unit/UsersTest.php

The UsersTest::testSaveUser functions above is about the what we expect from Users::saveUser function.

Fixtures in Yii Framework
Lastly, we mostly need fixtures for data operations. Yii developers have already thought that and have given a method to make it easy. Suppose that you have a model with name “Users” and this model is related to “Users” table in database then create a file with name “Users.php” under fixtures folder and put the lines in the below format.

return array(
‘user1′=>array(
‘password’=>md5(12345),
‘realname’=>’Test User’,
‘email’=>’test@test.com’,
),
‘user2′=>array(
‘password’=>md5(12345),
‘realname’=>’Test User 2′,
‘email’=>’test2@test.com’,
),
‘user3′=>array(
‘password’=>md5(12345),
‘realname’=>’Test User 3′,
‘email’=>’test3@test.com’,
),
// add as many as you want
);

then add the below member to related test class(UsersTest.php)

public $fixtures=array(
‘users’=>’Users’,
// you can other elements if it is exists for instance
// ‘comments’ => ‘Comments’
);

Fixture names(users) allow us to access the fixture data in test methods(testSaveUser) in a convenient way. The following code shows its typical usage:

// return all rows in the ‘Users’ fixture table
$users = $this->users;
// return the row whose alias is ‘user1′ in the `Users` fixture table
$user = $this->users['user1'];
// return the AR instance representing the ‘user1′ fixture data row
$user = $this->users(‘user1′);

We can save fixture data to table or manipulate data operations.

I think, if you are new to writing tests or not even write test codes yet. This concept may become a little hard to understand. Thus don’t give up, keep studying other fundamental sources in internet…

Ahmet Oguz Mermerkaya

About the Author:

1 Comment + Add Comment

Leave a comment

Partners