User Tools

Site Tools


wiki:tdd

PHP Test Driven Development Playpen

I have created a very basic UnitTest class which does a few simple things:

  • Checks for:
    • boolean
    • integer
    • strings
    • regular expression match, in xml
  • Sets headers to break the tests up
  • Gives you a result set

The code is as follows:

<?php
class UnitTest {
	public function __construct() {
		$this->total_tests = 0;
		$this->total_success = 0;
		$this->total_failure = 0;
		$this->output = "";
	}
	public function Run($test,$result,$datatype,$expected="") {
		if ($datatype == "bool") {			
			if ($result) {
				if ($result == $expected) {
					$this->ShowResult($test,"Success");
					$this->total_success++;
				}
				else {				
					$this->ShowResult($test,"Failed");
					$this->total_failure++;
				}
			}
			else {				
				$this->ShowResult($test,"Failed");
				$this->total_failure++;
			}
		}
		if ($datatype == "integer") {			
			if (IS_NUMERIC($result)) {
				$this->ShowResult($test,"Success");
				$this->total_success++;
			}
			else {				
				$this->ShowResult($test,"Failed");
				$this->total_failure++;
			}
		}
		if ($datatype == "string") {			
			if ($result == $expected) {
				$this->ShowResult($test,"Success");
				$this->total_success++;
			}
			else {				
				$this->ShowResult($test,"Failed");
				$this->total_failure++;
			}
		}
		if ($datatype == "xml") {			
			if (preg_match("/$expected/",$result)) {
				$this->ShowResult($test,"Success");
				$this->total_success++;
			}
			else {				
				$this->ShowResult($test,"Failed");
				$this->total_failure++;
			}
		}
	}	
	public function SetHeader($v) {
		$this->output .= "<h3>$v</h3><br />\n";
	}
	private function ShowResult($test,$result) {
		$this->total_tests++;
		$this->output .= "$test - $result<br />\n";
	}
	public function Result() {
		echo "Total tests run: ".$this->total_tests."<br />\n";
		echo "Total success  : ".$this->total_success."<br />\n";
		echo "Total failure  : ".$this->total_failure."<br />\n";
		echo "<hr >\n";
		echo $this->output;
	}
}
?>

How do you use it? Quite simple really.

<?php
$unittest->SetHeader("<h1>USERMASTER TEST DRIVEN UNIT TESTING</h1>\n");
$unittest->Run("ADD USER",$result,"bool",true);
echo $unittest->Result();
?>

In the above example, $result is the result you expect. Here's an example of a user class I created, which you can use.

<?php
class UserMaster {
	function __construct() {
		/* SET CHECKING TO FALSE */
		$this->parameter_check=False;
		$this->params_add = array("userlogin","password","fullname");
		$this->vartypes_add = array("userlogin"=>"email","password"=>"any","fullname"=>"a-z");
		$this->params_edit = array("userid","fullname","timezone");
		$this->vartypes_edit = array("userid"=>"numeric","fullname"=>"a-z","timezone"=>"any",);
		$this->errors = "";
		$this->send_add_email = true;
		$this->debug  = false;
	}
	public function GetVar($v) {
		if (ISSET($this->$v)) {
			return $this->$v;
		}
		else {
			return "";
		}
	}	
	public function SetVar($v,$val) {
		$this->$v = $val;
	}
	public function Add() {		
		if (!$this->CheckVarsSet("add")) {
			$this->debug("Failed to provide correct params");
			return false;
		}
		
		if (!$this->CheckVars($this->vartypes_add)) {
			$this->debug("Invalid data types");
			$this->Errors("Invalid data");
			return false;
		}		
		
		$sp_params = "";
		foreach ($this->params_add as $p) {
		  $sp_params .= "'".$this->$p."',";
		}
		$sp_params = substr($sp_params,0,-1);
		$sql = "call sp_usermaster_add($sp_params)"; // this is a stored procedure
		$this->debug($sql);
		$result = $GLOBALS['db']->Query($sql);
		if (!$result) {
			$this->Errors(' Could not execute query ');
			return false;				
		}
		else {
			while ($row = $GLOBALS['db']->FetchArray($result)) {
				$this->userid = $row['userid']; // return the userid from your database
				$this->debug(" Worked! ");
				return true;
			}			
		}	
		else {	
			$this->debug(" Something bad happened! ");
			return false;
		}
	}

	// CHECK VARS ALL SET FOR REQUIRED METHOD
	private function CheckVarsSet($method) {    
		if ($method == "add") {			
			foreach ($this->params_add as $param) {
				if (!ISSET($this->$param)) {
					$this->Errors("Parameter $param not set");
					return False;
				}
			}
		}
		if ($method == "edit") {
			foreach ($this->params_edit as $param) {
				if (!ISSET($this->$param)) {
					$this->Errors("Parameter $param not set");
					return False;
				}
			}
		}
    return True;
  }
    // CHECK VAR TYPES
  private function CheckVars($vartypes) {
	$count = 0;
    foreach ($vartypes as $var=>$type) {	
      if ($type == "a-z" && !preg_match("/^[A-Z0-9._%+-@ ]*$/i",$this->$var)) {                
        $this->Errors($var." needs to contain alpha characters only");
		$this->debug($var." needs to be $type, you provided: ".$this->$var);
        return False;
      }      
      if ($type == "numeric" && !IS_NUMERIC($this->$var)) {
        $this->Errors($this->$var." needs to be numeric");
		$this->debug($var." needs to be $type, you provided: ".$this->$var);
        return False;        
      }
	  if ($type == "email" && !preg_match("/^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}$/i",$this->$var)) {
        $this->Errors($var." needs to be an email address, you provided: ".$this->$var);
		$this->debug($var." needs to be $type, you provided: ".$this->$var);
        return False;        
      }
	  // for any
	  return true;
	  $count++;
    }
    return True;
  }

	function Errors($err) {
		$this->errors.=$err."\n";
	}

	function ShowErrors() {
		return $this->errors;
	}
	private function debug($msg) {
		if ($this->debug) {
			echo $msg."<br />\n";
		}
	}
}
?>

It's a little complex, and I'd probably prefer to move the CheckVars to it's own class and extend it, but this should give you enough to go on.

wiki/tdd.txt · Last modified: 2015/06/22 05:58 by terence