PHPUnit Testing
Posted On April 9, 2008 by Anush filed under Programming
What is Unit testing?
Unit test is a test designed to evaluate a single element of code. The code’s behavior is examined independently of other elements in order to determine whether the code element meets expectations. A suite of unit tests can be used to evaluate an entire solution (one unit at a time). Then, if the solution itself ceases to be effective, it can be broken down into its component actions.
While integrating code in an application or identifying bugs that have migrated into production code unexpectedly, unit tests can save developers and project managers hours of work.
There are two types of units in object-oriented programming (OOP) that apply to unit testing. Unit testing will always be defined as being within the scope of one of these two elements – ‘class’ and ‘method’. A class comprises properties and methods. A method is a behavior taken by a class. A class is defined as the sum of its members and methods.
PHPUnit is a small application that can be used to automatically test PHP units. PHP unit is written in PHP language itself. The advantage of using PHP itself as the testing language is that there are no new languages to learn. Testing can start straight away and the developer can test any part of the code. Basically, all parts that can be accessed by the application code can also be accessed by the test code if they are in the same language.
If you are testing the PHP Unit testing for the fist time, it is recommended that you follow the following steps. To run the programs, you need a text pad and Apache web server. Also, you have to include PHP Unit.
PHPUnit is a regression-testing framework used by the developer who implements unit tests in PHP. This is the version to be used with PHP 4 and above.
Now we will write a test for validating username, password, confirm password and Email ID.
Add all the validations into the validator.php file. Refer code 1.
Code- 1
| <?php /** * Validator superclass for form validation */ class Validator { /** * Private * $errorMsg stores error messages if not valid */ var $errorMsg; //! A constructor. /** * Constucts a new Validator object */ function Validator () { $this->errorMsg=array(); $this->validate(); } //! A manipulator /** * @return void */ function validate() { // Superclass method does nothing } //! A manipulator /** * Adds an error message to the array * @return void */ function setError ($msg) { $this->errorMsg[]=$msg; } //! An accessor /** * Returns true is string valid, false if not * @return boolean */ function isValid () { if ( isset ($this->errorMsg) ) { return false; } else { return true; } } //! An accessor /** * Pops the last error message off the array * @return string */ function getError () { return array_pop($this->errorMsg); } } /** * ValidatorUser subclass of Validator * Validates a username */ class ValidateUser extends Validator { /** * Private * $user the username to validate */ var $user; //! A constructor. /** * Constucts a new ValidateUser object * @param $user the string to validate */ function ValidateUser ($user) { $this->user=$user; Validator::Validator(); } //! A manipulator /** * Validates a username * @return void */ function validate() { if (!preg_match('/^[a-zA-Z0-9_]+$/',$this->user )) { $this->setError('Username contains invalid characters'); } if (strlen($this->user) < 6 ) { $this->setError('Username is too short'); } if (strlen($this->user) > 20 ) { $this->setError('Username is too long'); } } } /** * ValidatorPassword subclass of Validator * Validates a password */ class ValidatePassword extends Validator { /** * Private * $pass the password to validate */ var $pass; /** * Private * $conf to confirm the passwords match */ var $conf; //! A constructor. /** * Constucts a new ValidatePassword object subclass or Validator * @param $pass the string to validate * @param $conf to compare with $pass for confirmation */ function ValidatePassword ($pass,$conf) { $this->pass=$pass; $this->conf=$conf; Validator::Validator(); } //! A manipulator /** * Validates a password * @return void */ function validate() { if ($this->pass!=$this->conf) { $this->setError('Passwords do not match'); } if (!preg_match('/^[a-zA-Z0-9_]+$/',$this->pass )) { $this->setError('Password contains invalid characters'); } if (strlen($this->pass) < 6 ) { $this->setError('Password is too short'); } if (strlen($this->pass) > 20 ) { $this->setError('Password is too long'); } } } /** * ValidatorEmail subclass of Validator * Validates an email address */ class ValidateEmail extends Validator { /** * Private * $email the email address to validate */ var $email; //! A constructor. /** * Constucts a new ValidateEmail object subclass or Validator * @param $email the string to validate */ function ValidateEmail ($email){ $this->email=$email; Validator::Validator(); } //! A manipulator /** * Validates an email address * @return void */ function validate() { $pattern= "/^([a-zA-Z0-9])+([\.a-zA-Z0-9_-])*@([a-zA-Z0-9_-])+(\.[a-zA-Z0-9_-]+)+/"; if(!preg_match($pattern,$this->email)){ $this->setError('Invalid email address'); } if (strlen($this->email)>75){ $this->setError('Address is too long'); } } } ?> ...................................................................................... |
In the above code (validator.php), the Validator class includes standard tests for ValidateUser, ValidatePassword and ValidateEmail. All these test the typical expectations of what you would expect as the result of a function or method to be. This is by far the most common type of test in the daily routine of development, making up about 95% of test cases.
Now we will add the script for validating usertest. Name the file as ValidateUserTest.php (code 2).
Code-2
| ...................................................................................... <?php // This script is ValidateUserTest.php // Include the code to be tested require_once ('../lib/Validator.php'); // Tests the ValidateUser class class ValidateUserTest extends Test { var $validator; // Instance of class to test // Instantiate validator function ValidateUserTest() { // Instantiate the class to be tested $this->validator= new ValidateUser('username'); } // Test a valid username function testValidUser () { // Method should return true so test with Assert::equalsTrue Assert::equalsTrue($this->validator->isValid(), 'User is valid but returned isValid() false'); } // Test username containing invalid characters function testInvalidChars () { // Reset the errors $this->validator->errors=array(); // Set test data $this->validator->user='user%name'; // As this is called by a constructor, call it again $this->validator->validate(); // Method should return false so test with Assert::equalsFalse Assert::equalsFalse($this->validator->isValid(), 'User contains bad chars but isValid() returned true'); } // Test username that is too short function testInvalidShort () { // Reset the errors $this->validator->errors=array(); // Set test data $this->validator->user='user'; // As this is called by a constructor, call it again $this->validator->validate(); // Method should return false so test with Assert::equalsFalse Assert::equalsFalse($this->validator->isValid(), 'User is too short but isValid() returned true'); } // Test username that is too long function testInvalidLong () { // Reset the errors $this->validator->errors=array(); // Set test data $this->validator->user='usernameusernameusername'; // As this is called by a constructor, call it again $this->validator->validate(); // Method should return false so test with Assert::equalsFalse Assert::equalsFalse($this->validator->isValid(), 'User is too long but isValid() returned true'); } } ?> |
Code- 3 validates useremail. Add the code in ValidateEmailTest.php.
| ..................................................................................... <?php require_once ('../lib/Validator.php'); // Tests the ValidateEmail class class ValidateEmailTest extends Test { var $validator; function ValidateEmailTest() { $this->validator= new ValidateEmail('name@domain.com'); } function testValidEmail () { $this->validator->validate(); Assert::equalsTrue($this->validator->isValid(), 'Email is valid but returned isValid() false'); } function testInvalidChars () { $this->validator->errors=array(); $this->validator->email='name_domain.com'; $this->validator->validate(); Assert::equalsFalse($this->validator->isValid(), 'Email contains bad chars but isValid() returned true'); } function testInvalidLong () { $this->validator->errors=array(); $this->validator->email=str_pad('name@domain.com',86, 'pad',STR_PAD_LEFT); $this->validator->validate(); Assert::equalsFalse($this->validator->isValid(), 'Email is too long but isValid() returned true'); } } ?> |
The below script (code 4) validates the Password. Append the following code in
ValidatePasswordTest.php.
| ..................................................................................... <?php require_once ('../lib/Validator.php'); // Tests the ValidatePassword class class ValidatePasswordTest extends Test { var $validator; function ValidatePasswordTest() { $this->validator= new ValidatePassword('password','password'); } function testValidPassword () { $this->validator->validate(); Assert::equalsTrue($this->validator->isValid(), 'Password is valid but returned isValid() false'); } function testInvalidChars () { $this->validator->errors=array(); $this->validator->pass='pass%word'; $this->validator->conf='pass%word'; $this->validator->validate(); Assert::equalsFalse($this->validator->isValid(), 'Password contains bad chars but isValid() returned true'); } function testInvalidShort () { $this->validator->errors=array(); $this->validator->pass='pass'; $this->validator->conf='pass'; $this->validator->validate(); Assert::equalsFalse($this->validator->isValid(), 'Password is too short but isValid() returned true'); } function testInvalidLong () { $this->validator->errors=array(); $this->validator->pass='passwordpasswordpassword'; $this->validator->conf='passwordpasswordpassword'; $this->validator->validate(); Assert::equalsFalse($this->validator->isValid(), 'Password is too long but isValid() returned true'); } function testMismatch () { $this->validator->errors=array(); $this->validator->pass='password'; $this->validator->conf='mismatch'; $this->validator->validate(); Assert::equalsFalse($this->validator->isValid(), 'Passwords do not match but isValid() returned true'); } } ?> |
Now will add the final code in the index.php file. Refer code 5.
Code 5
| ..................................................................................... <?php if ( $_POST['register'] ) { require_once('lib/Validator.php'); // Register the subclasses to use $v['u']=new ValidateUser($_POST['user']); $v['p']=new ValidatePassword($_POST['pass'],$_POST['conf']); $v['e']=new ValidateEmail($_POST['email']); // Perform each validation foreach($v as $validator) { if (!$validator->isValid()) { while ($error=$validator->getError()) { $errorMsg.="<li>".$error."</li>\n"; } } } if (isset($errorMsg)) { print ("<p>There were errors:<ul>\n".$errorMsg."</ul>"); } else { print ('<h2>This Form is Valid!</h2>'); } } else { ?> <h2>Create Your Account Details</h2> <form action="<?php echo ($_SERVER['PHP_SELF']); ?>" method="post"> <p>Enter your name: <input type="text" name="user"></p> <p>Enter your Password: <input type="password" name="pass"></p> <p>Enter your Confirm Password : <input type="password" name="conf"></p> <p>Enter your Email: <input type="text" name="email"></p> <p><input type="submit" name="register" value=" Register "></p> </form> <?php } ?> |
Finally, you can execute the code from index.php file! When you view the file in the browser, it will accept the username, password, confirm password and email. In case if you make any mistake, it will show errors.
You can also download the source code from the following URL: http://www.developeriq.com/downloads/phpunit.zip.
Conclusion
Unit testing is very important in the development life cycle of any software. It improves performance of the software as well as productivity of the developer. It saves time over a period of few months as developers gain focus on resolving the coding problem.
You can reach Ajit Kumar at: ajit_2006_kumar_20@hotmail.com.
Comments
Satya61229 commented, on May 30, 2008 at 1:20 p.m.:
http://www.developeriq.com/downloads/... is not working

Ch Shankar commented, on April 11, 2008 at 1:04 p.m.:
Its a fine article. DIQ is good.