PHPUnit
PHPUnit provides a simple framework for creating a test suite to automate testing of functions and classes.PHPUnit is for to test small software components as often and early as possible, this way we will not have to fix bugs and errors in the API while setting up and testing larger applications which depend on the class.
PHPUnit stands alone as a good tool for testing classes or a set of functions and will ease your development cycle and help you to avoid endless debug sessions.
WORK UNIT
Normally, we would write a class, do some unsystematic tests using echo() or var_dump() or print_r(). After this, we use the class in your application and hope everything is ok. To benefit from PHPUnit you should rethink the flow. The best way is to do this:- 1. design your class/API
- 2. create a test suite
- 3. implement the class/API
- 4. run the test suite
- 5. fix failures or errors and go to #4 again
INSTALLATION
Installing PHPUnit
There a three supported ways of installing PHPUnit. You can use the PEAR Installer or Composer to download and install PHPUnit as well as its dependencies. You can also download a PHP Archive (PHAR) of PHPUnit that has all required (as well as some optional) dependencies of PHPUnit bundled in a single file.
PHPUnit 3.7 requires PHP 5.3.3 (or later) but PHP 5.4.7 (or later) is highly recommended.
We are linux user so we’ve used PEAR to install PhpUnit, If PEAR is not available so can install PEAR by following commands.
Installing PEAR
Getting and installing the PEAR package manager
1. If Pear is not available
Install PEAR by using following cammands
wget http://pear.php.net/go-pear.phar
php go-pear.phar
After installing PEAR we can now Install PHPUnit
For installing PHPUnit use the following commands
pear config-set auto_discover 1
pear install pear.phpunit.de/PHPUnit
Out put
install ok: channel://pear.phpunit.de/File_Iterator-1.3.3
install ok: channel://pear.phpunit.de/Text_Template-1.1.4
install ok: channel://pear.phpunit.de/PHP_Timer-1.0.4
install ok: channel://pear.symfony.com/Yaml-2.1.7
install ok: channel://pear.phpunit.de/PHP_TokenStream-1.1.5
install ok: channel://pear.phpunit.de/PHP_CodeCoverage-1.2.7
install ok: channel://pear.phpunit.de/PHPUnit_MockObject-1.2.3
install ok: channel://pear.phpunit.de/PHPUnit-3.7.13
The above will install PhpUnit
Explaining how to design Class and writing and running the test suits for Class.
Real example of PHPUnit
We are taking a simple example to explain how to writing and running the test suits for Class.
Design a class
---- string.php ----
<?php
class String
{
//contains the internal data
var $data;
// constructor
function String($data) {
$this->data = $data;
}
// creates a deep copy of the string object
function copy() {
}
// adds another string object to this class
function add($string) {
}
// returns the formated string
function toString($format) {
}
}?>
Creating test suite
Now we can create a test suite, which checks every function of your string class. A test suite is normal PHP class inherited from PHPUnit_TestCase containing test functions, identified by a leading 'test' in the function name. In the test function an expected value has to be compared with the result of the function to test. The result of this compare must delegate to a function of the assert*()-family, which decides if a function passes or fails the test.
---- testcase.php ----
<?php
require_once 'string.php';
class StackTest extends PHPUnit_Framework_TestCase
{
// contains the object handle of the string class
var $abc;
// constructor of the test suite
public function StringTest($name) {
$this->PHPUnit_Framework_TestCase($name);
}
// called before the test functions will be executed
// this function is defined in PHPUnit_TestCase and overwritten
// here
public function setUp() {
// create a new instance of String with the
// string 'abc'
$this->abc = new String("abc");
}
// called after the test functions are executed
// this function is defined in PHPUnit_TestCase and overwritten
// here
public function tearDown() {
// delete your instance
unset($this->abc);
}
public function testToString() {
$result = $this->abc->toString('contains %s');
$expected = 'contains abc';
$this->assertTrue($result == $expected);
}
// test the copy function
public function testCopy() {
$abc2 = $this->abc->copy();
$this->assertEquals($abc2, $this->abc);
}
// test the add function
public function testAdd() {
$abc2 = new String('123');
$this->abc->add($abc2);
$result = $this->abc->toString("%s");
$expected = "abc123";
$this->assertTrue($result == $expected);
}
//$this->assertEquals('foosss', $stack[count($stack)-1]);
}
?>
The first test run
Run it from Command Line By using below make sure you are on same path where this file is
phpunit testcase.php
If you call this script from the commandline, you will get the following output:
FFF
Time: 0 seconds, Memory: 2.50Mb
There were 3 failures:
1) StackTest::testToString
Failed asserting that false is true.
/var/www/html/phpunit/testcase.php:35
2) StackTest::testCopy
String Object (...) does not match expected type "NULL".
/var/www/html/phpunit/testcase.php:41
3) StackTest::testAdd
Failed asserting that false is true.
/var/www/html/phpunit/testcase.php:50
FAILURES!
Tests: 3, Assertions: 3, Failures: 3.
Every function fails the test, because your string functions didn't returned what we defined as the expected value.
Now you can make changes in your script.php as below
<?php
class String
{
//contains the internal data
var $data;
// constructor
function String($data) {
$this->data = $data;
}
// creates a deep copy of the string object
function copy() {
$ret = new String($this->data);
return $ret;
}
// adds another string object to this class
function add($string) {
$this->data = $this->data.$string->toString("%s");
}
// returns the formated string
function toString($format) {
$ret = sprintf($format, $this->data);
return $ret;
}
}
?>
And try Run the test case again,
phpunit testcase.php
the output would be
PHPUnit 3.7.13 by Sebastian Bergmann.
...
Time: 0 seconds, Memory: 2.50Mb
OK (3 tests, 3 assertions)
The Command-Line Test Runner
To run any test case we need to use “phpunit file name” command.
As we run this command we will see below result
PHPUnit 3.7.0 by Sebastian Bergmann.
..
Time: 0 seconds
OK (2 tests, 2 assertions)
Sebastian Bergmann is the creator of PHPUnit
. => Printed when the test succeeds.
F => Printed when an assertion fails while running the test method.
E => Printed when an error occurs while running the test method.
S => Printed when the test has been skipped.
I => Printed when the test is marked as being incomplete or not yet implemented.
Database Testing:
DB testing requires extension DbUnit.
The DbUnit extension considerably simplifies the setup of a database for testing purposes and allows you to verify the contents of a database after performing a series of operations.It can be installed like this:
pear install phpunit/DbUnit
downloading DbUnit-1.2.2.tgz ...
Starting to download DbUnit-1.2.2.tgz (41,888 bytes)
............done: 41,888 bytes
install ok: channel://pear.phpunit.de/DbUnit-1.2.2
DbUnit currently supports MySQL, PostgreSQL, Oracle and SQLite.
Configuration of a PHPUnit Database TestCase
If you want to test code that works with the Database Extension than require you to implement two abstract methods getConnection() and getDataSet().which resides in PHPUnit/Extensions/Database/TestCase.php
So we have to include “ PHPUnit/Extensions/Database/TestCase.php” file
require_once "PHPUnit/Extensions/Database/TestCase.php
require_once "PHPUnit/Extensions/Database/TestCase.php";
class MyGuestbookTest extends PHPUnit_Extensions_Database_TestCase
{
/**
* @return PHPUnit_Extensions_Database_DB_IDatabaseConnection
*/
public function getConnection()
{
$pdo = new PDO("mysql:host=localhost;dbname=bulletproof",
"root", "neova123");
return $this->createDefaultDBConnection($pdo,
"bulletproof"); }
/**
* @return PHPUnit_Extensions_Database_DataSet_IDataSet
*/
public function getDataSet()
{
return $this->createXMLDataSet("seed.xml");
}
}
getConnection(): This is to get connected with Database.
getDataSet():The getDataSet() method defines how the initial state of the database should look before each test is executed.
Example:
public function testSaveArticle() {
$article = new ArticleDAO();
$article->save(array(
"title" => "PHP",
"description" => "PHP",
"content" => "PHP",
"preview_image" => "PHP",
"section_id" => "PHP",
));
$resultingTable = $this->getConnection()->createQueryTable("articles","SELECT * FROM articles");
$expectedTable =this->createXmlDataSet("expectedArticles.xml")->getTable("articles");
$this->assertTablesEqual($expectedTable,$resultingTable);
}
I have a BankAccount Example where we can be prity clear how and where to write Test cases in a real scenarios.
<?php
require_once 'BankAccount.php';class BankAccountTest extends PHPUnit_Framework_TestCase
{
protected $ba;
protected function setUp()
{
$this->ba = new BankAccount;
}
public function testBalanceIsInitiallyZero()
{
$this->assertEquals(0, $this->ba->getBalance());
}
public function testBalanceCannotBecomeNegative()
{
try {
$this->ba->withdrawMoney(1);
}
catch (BankAccountException $e) {
$this->assertEquals(0, $this->ba->getBalance());
return;
}
$this->fail();
}
public function testBalanceCannotBecomeNegative2()
{
try {
$this->ba->depositMoney(-1);
}
catch (BankAccountException $e) {
$this->assertEquals(0, $this->ba->getBalance());
return;
}
$this->fail();
}
}
?>
Skeleton Generator
The PHPUnit Skeleton Generator is a tool that can generate skeleton test classes from production code classes and vice versa. It can be installed using the following command:
pear install phpunit/PHPUnit_SkeletonGenerator
Example calculator.php
<?php
class Calculator
{
public function add($a, $b)
{
return $a + $b;
}
}
?>
by using below command you can generate skeleton for calculator.php
phpunit-skelgen --test Calculator
This will create a new file named calculatorTest.php
<?php
/**
* Generated by PHPUnit_SkeletonGenerator 1.2.0 on 2013-01-28 at 11:42:17.
*/
class calculatorTest extends PHPUnit_Framework_TestCase
{
/**
* @var calculator
*/
protected $object;
/**
* Sets up the fixture, for example, opens a network connection.
* This method is called before a test is executed.
*/
protected function setUp()
{
$this->object = new calculator;
}
/**
* Tears down the fixture, for example, closes a network connection.
* This method is called after a test is executed.
*/
protected function tearDown()
{
}
public function testAdd() {
$o = new Calculator;$this->assertEquals(0, $o->add(0, 0));
}
}