SiteMinder / Webhosting
The Computer Merchant, Ltd
US-MA-North Quincy

Justtechjobs.com Post A Job | Post A Resume

Debugging PHP
Introduction
The debugging process is a time consuming activity. When the project is a small group of scripts all is easy, but when the size and complexity of the project grows, the debugging time increases dramatically. With PhpUnit you can speed up your debugging process.
PhpUnit is a PHP port of JUnit test framework wrote by Fred Yankowski , you can download it from http://www.ontosys.com/phiki/PhpUnit. With PhpUnit you can write a suite of tests to check the correctness of your code like a security harness. After the creation of the test suite you can run all the tests automatically in a single step.
When you detect a bug, you can write a test to catch it. If the same bug is introduced again you will detect it as soon as you run your test suite. If you run the test suite frequently your will increase the robustness of your code.
Getting started
Suppose we want to write a test suite for our simple Account class.

<?php

class Account{
  var
$balance;

  function
Account($initialBalance=0){
    
$this->balance = $initialBalance;
  }
  
  function
withdraw($amount){
    
$this->balance -= $amount;
  }
  
  function
deposit($amount){
    
$this->balance += $amount;
  }
  
  function
getBalance(){
    return
$this->balance;
  }

  function
transferFrom(&$sourceAccount,$amount){
    
$sourceAccount->withdraw($amount);
    
$this->deposit($amount);
  }
?>
Creating the test class
The first step is the creation of AccountTester class as a subclass of TestCase class provided by PhpUnit.
The TestCase class has two methods, setUp and tearDown, that are interesting to us. Both methods have an empty implementation in the TetsCase class and must be overridden in order to be used.
The setUp method is used for initialization stuff. In our case we used to initialize the sample accounts used in our tests.The tearDown method is used for clean up stuff, we don't need it for our tests. Our AccountTester class looks like this:

<?php

class AccountTester extends TestCase{
  
  var
$_ac1;
  var
$_ac2;
  var
$_ac3;
  var
$_ac4;
  
  function
AccountTester($name){
    
$this->TestCase($name); // call parent constructor
  
}

  
  function
setUp(){
    
    
// data  for testWithdraw
    
$this->_ac1 = new Account(100);  
    
    
// data for  testDeposit
    
$this->_ac2 = new Account(20);  
    
    
// data for  testTransferFrom
    
$this->_ac3 = new Account(30);  
    
$this->_ac4 = new Account(50);  
  }
}

?>
Adding Individual Tests
Now we must add our first test methods to AccountTester class.

<?php

// Make a withdrawal of 25 units from _ac1.
// _ac1's initial balance is  100

function testWithdraw(){
    
$this->_ac1->withdraw(25);
    
$this->assert($this->_ac1->getBalance() == 75); // 100 - 25 = 75
}

// Make a deposit of 10 units into _ac2.
// _ac1's initial balance is  20

function testDeposit(){
    
$this->_ac2->deposit(10);
    
$this->assertEquals(30,$this->_ac2->getBalance()); //20 +10 = 30
}
  
//  Tranfers 10 units from _ac3 to _ac4
//  _ac3's initial balance is  30
//  _ac4's initial balance is  50

function testTransferFrom(){
    
$this->_ac4->transferFrom(&$this->_ac3,10);
    
$this->assertEquals(20,$this->_ac3->getBalance(),"Source account balance incorrect"); // 30 - 10 = 20
    
$this->assertEquals(60,$this->_ac4->getBalance(),"Target account balance incorrect"); // 50 + 10 = 60
}

?>
The key of the test is the assert method. If the expression inside the assert is true the test is passed, otherwise an error as occurred.
A lot of asserts check for the equality of two values, for this reason the the TestCase class has a assertEquals method. The assertEqual method has three parameters: the expected value, the actual value, and a optional message to be printed if the test fails.
Running The Test
The time to run our test has arrived, we must write a script to run the tests. We create a runtest.php and put the following lines of code inside it:

<?php

//creation of  the test suite object
$tSuite = new TestSuite();

//Add inidividual tests
$tSuite->addtest(new AccountTester("testWithdraw"));
$tSuite->addtest(new AccountTester("testDeposit"));
$tSuite->addtest(new AccountTester("testTransferFrom"));

//Creation of the Result
$res = new TextTestResult();

//Run of the test
$tSuite->run(&$res);

//Print results
$res->report();

?>
After the creation of the TestSuite object we must add each test to the suite. The parameter of the AccountTester's constructor is the name of the test method that we want to execute.
The results of the tests are encapsulated in the TestResult class. In order to output the results of the test we use the TextTestResult class provided by PhpUnit. The TextTestResult is a specialization of TestResult for the creation of text/html reports. We can write our customized subclasses of TestResult if we need more control over the output.
In the last lines we run the test and print the results.
Tips and tricks
When you write a new test, introduce a little bug to be sure that the test is working correctly.
For example, we can introduce a little bug into our Account class.

<?php

function withdraw($amount){
    
$this->balance -= $Amount; // Variable name misspelled
}
  
?>
Now we run the tests and we can see quickly if the error is detected.
Write tests for relevant methods, you don't need a test for each method in your class.
Write the tests before you start programming. This will give you better understanding of how your code must work.
Now you can see how the bug hunting time is reduced, increasing your efficiency as a programmer. Happy hunting!
-- Oier