Unit Testing using a framework

Discussion of testing theory and practice, including methodologies (such as TDD, BDD, DDD, Agile, XP) and software - anything to do with testing goes here. (Formerly "The Testing Side of Development")

Moderator: General Moderators

Post Reply
Skeptical
Forum Newbie
Posts: 8
Joined: Mon Sep 18, 2006 10:23 pm

Unit Testing using a framework

Post by Skeptical »

feyd | Please use

Code: Select all

,

Code: Select all

and [syntax="..."] tags where appropriate when posting code. Your post has been edited to reflect how we'd like it posted. Please read:  [url=http://forums.devnetwork.net/viewtopic.php?t=21171]Posting Code in the Forums[/url] to learn how to do it too.[/color]


My programmers are having trouble running unit tests on classes based on frameworks (such as CodeIgniter, PHP Cake, etc.).  Basically they're saying that there are lots of dependencies and it's all under on huge class.

Can you guys take a look at the following source code and let me know how this could get tested?
 
How would you test the various classes, such as:
[list]
[*]the "DbMySQL" class, located in system/drivers/Dbmysql.class.php
[*]the "Welcome" class, located in frame/modules/welcome/welcome.php[/list](btw, the code doesn't actully run, it's just for example purposes)
 
[b]FILE: config.inc.php[/b]

Code: Select all

<?php
if (!defined('BASEPATH')) exit('No direct script access allowed!');
 
 
 
$cfg['version'] = 0.3;
/**
* not complete just an example
*/
$cfg['site']['webmaster_name'] = 'Webmaster'; // webmaster name
 
/**
* core driver class that auto append to any other driver classes
*/
$cfg['drivers']['core'] = array('template' => 'tpl', 'database' => 'db');
$cfg['drivers']['basic'] = array('misc' => 'misc' , 'validata' => 'check', 'sendmail' => 'email', 'privacy' => 'prv');
/**
* program basic config settings
*/
$cfg['base']['DefaultControler'] = 'Welcome'; // Default site use controler;
$cfg['base']['DefaultMethod'] = 'index'; // Default method used in controler;

FILE: index.php

Code: Select all

<?php
 
 
error_reporting(E_ALL);
if (PHP_VERSION < 5) exit('Need Version 5 Plus!');
 
function get_microtime()
{
  list($usec, $sec) = explode(" ", microtime());
  return ((float)$usec + (float)$sec);
}
 
$time_start = get_microtime();
// system folder where the core framework need to run
$system_folder = 'system';
// applcation folder that application locate here
$frame_folder = 'frame';
define('ROOTPATH', (function_exists('realpath') AND @realpath(dirname(__FILE__)) !== false) ? realpath(dirname(__FILE__)) . DIRECTORY_SEPARATOR : '.' . DIRECTORY_SEPARATOR);
define('BASEPATH', ROOTPATH . $system_folder . DIRECTORY_SEPARATOR);
define('APPPATH', ROOTPATH . $frame_folder . DIRECTORY_SEPARATOR);
define('TRIGGER', 'faction');
define('SITE_DOMAIN', 'tigger.com'); // site domain defined here;
define('DEBUG', 'Both'); // Both || ScreenOnly || FileOnly || None
// -------------------------
ob_start();
// turn off run-time magic quotes
set_magic_quotes_runtime(0);
// run our frame work
require_once(BASEPATH . 'base.php');

FILE: frame/controllers/welcome.php

Code: Select all

<?php
if (!defined('BASEPATH')) exit('No direct script access allowed!');
 
 
 
class Welcome extends Controller
{
  /**
   * Welcome::index()
   *
   * @return
   */
  function index()
  {
      $this->welcome();
  }
  function welcome()
  {
      $this->loadmodule('welcome');
      $this->module->action();
  }
}
 
?>

FILE: frame/modules/welcome/welcome.php

Code: Select all

<?php
if (!defined('BASEPATH')) exit('No direct script access allowed!');
 
 
 
class Welcome extends Controller
{
  /**
   * Welcome::index()
   *
   * @return
   */
  function index()
  {
      $this->welcome();
  }
  function welcome()
  {
      $this->loadmodule('welcome');
      $this->module->action();
  }
}
 
?>

FILE: system/configs/database.cfg.php

Code: Select all

<?php
if (!defined('BASEPATH')) exit('No direct script access allowed!');
$cfg['_class_name'] = 'db';
$cfg['_driver'] = 'dbmysql';
 
$cfg['_setting'] = 'default';
 
$cfg['default']['hostname'] = 'localhost';
$cfg['default']['username'] = 'yourname';
$cfg['default']['password'] = 'yourpass';
$cfg['default']['database'] = 'yourdatabase';
$cfg['default']['db_debug'] = true;

FILE: system/drivers/Dbmysql.class.php.php

Code: Select all

<?php
 
 
 
 
class DbMySQL
{
  protected $querycnt;
 
  /**
   * DbMySQL::__construct()
   *
   * @param mixed $cfg
   */
  function __construct($cfg = array())
  {
      $this->dbhost = $cfg['hostname'];
      $this->dbuser = $cfg['username'];
      $this->dbpass = $cfg['password'];
      $this->dbname = $cfg['database'];
      $this->_debug = $cfg['db_debug'];
      @mysql_connect($this->dbhost, $this->dbuser, $this->dbpass) OR _throw('Can not connect to MySQL server!');
      $this->selectdb();
  }
 
  /**
   * DbMySQL::version()
   *
   * @return
   */
  function version()
  {
      echo "<pre>/**
* MySQL
*
*/</pre>";
  }
 
  /**
   * DbMySQL::selectdb()
   *
   * @param mixed $dbname
   * @return null
   */
  public function selectdb($dbname = null)
  {
      @mysql_select_db($dbname == null ? $this->dbname:$dbname) OR _throw('Can not select to the database!');
  }
 
  /**
   * DbMySQL::query()
   *
   * @param mixed $sql
   * @return query resoucre;
   */
  public function query($query)
  {
      $this->querycnt++;
      $sql = @mysql_query($query);
      if ($sql)
      {
          return $sql;
      }
      else if ($this->_debug)
      {
          _throw('<span style="color:#FF0000;">Query Error :</span> <span style="color:#324F96;">' . htmlspecialchars($query) . '</span><br /><span style="color:#FF0000;">Error No.' . mysql_errno() . ' :</span> ' . htmlspecialchars(mysql_error()));
      }
  }
  /**
   *
   * other functions
   *
   */
 
}

FILE: system/libraries/Controller.php

Code: Select all

<?php
if (!defined('BASEPATH')) exit('No direct script access allowed!');
 
 
 
 
class Controller extends Base
{
  private static $module_loaded = array();
  /**
   * Controler::__construct()
   */
  function __construct()
  {
      parent::__construct();
      $this->modules = new stdClass();
  }
 
  /**
   * Controler::loadmodule()
   *
   * @param string $module => module name
   * @param string $branch => controler name
   * @return void
   */
  function loadmodule($module, $branch = false)
  {
      if ($branch === false)
      {
          $ctl_name = strtolower(get_class($this));
      }
      else
      {
          $ctl_name = strtolower($branch);
      }
      $module_name = ucfirst(strtolower($module));
      if (! isset(self::$module_loaded[$ctl_name][strtolower($module)]))
      {
          if (! include_once(APPPATH . 'modules/' . $ctl_name . '/' . strtolower($module) . '.php'))
          {
              _throw("Can't load '" . $module_name . "' module, file not found!");
          }
          if (! class_exists($module_name))
          {
              _throw("Module '" . $module_name . "' is not found!");
          }
          self::$module_loaded[$ctl_name][strtolower($module)] = &new $module_name();
      }
      $this->module = self::$module_loaded[$ctl_name][strtolower($module)];
      $this->modules->$module = self::$module_loaded[$ctl_name][strtolower($module)];
  }
}
 
?>

FILE: system/libraries/Router.php

Code: Select all

<?php
if (!defined('BASEPATH')) exit('No direct script access allowed!');
 
 
 
class Router
{
  /**
   * Router::__construct()
   *
   * init site configuration, get input direction convert to class and methods
   */
  public function __construct()
  {
      $this->faction = &_get_index();
      $this->config = _get_config('base');
      foreach(explode('.', $this->faction) as $key => $val)
      {
          if ($val != '')
          {
              $this->pieces[] = strtolower($val);
          }
      }
      $this->_set_class();
      $this->_set_method();
      $this->_output();
  }
 
  /**
   * Router::_output()
   * display pages
   *
   * @return void
   */
  private function _output()
  {
      $_method = &$this->_method;
      $class = &new $this->_class();
      $class->$_method();
  }
 
  /**
   * Router::_set_class()
   *
   * @return void
   */
  private function _set_class()
  {
      $this->_class = isset($this->pieces[0]) ? ucfirst(strtolower($this->pieces[0])):ucfirst(strtolower($this->config['DefaultControler']));
      if (! file_exists(APPPATH . 'controllers/' . strtolower($this->_class) . '.php'))
      {
          $this->_set_default_class();
      }
      else
      {
          include_once(APPPATH . 'controllers/' . strtolower($this->_class) . '.php');
          if (! class_exists($this->_class))
          {
              $this->_set_default_class();
          }
      }
  }
 
  /**
   * Router::_set_default_class()
   *
   * @return void
   */
  private function _set_default_class()
  {
      $this->_class = ucfirst(strtolower($this->config['DefaultControler']));
      if (file_exists(APPPATH . 'controllers/' . strtolower($this->_class) . '.php'))
      {
          include_once(APPPATH . 'controllers/' . strtolower($this->_class) . '.php');
          if (! class_exists($this->_class))
          {
              _throw('No default page class to handle');
          }
      }
      else
      {
          _throw('No default page to display!');
      }
  }
 
  /**
   * Router::_set_method()
   *
   * @return void
   */
  private function _set_method()
  {
      $this->_method = isset($this->pieces[1]) ? strtolower($this->pieces[1]):strtolower($this->config['DefaultMethod']);
      $class_methods = get_class_methods($this->_class);
      foreach($class_methods as $key => $val)
      {
          $class_methods[$key] = strtolower($val);
      }
      if (! in_array($this->_method, $class_methods))
      {
          $this->_method = strtolower($this->config['DefaultMethod']);
      }
      if (! in_array($this->_method, $class_methods))
      {
          $this->_set_default_class();
      }
  }
}
 
?>

feyd | Please use

Code: Select all

,

Code: Select all

and [syntax="..."] tags where appropriate when posting code. Your post has been edited to reflect how we'd like it posted. Please read:  [url=http://forums.devnetwork.net/viewtopic.php?t=21171]Posting Code in the Forums[/url] to learn how to do it too.[/color]
User avatar
Ollie Saunders
DevNet Master
Posts: 3179
Joined: Tue May 24, 2005 6:01 pm
Location: UK

Post by Ollie Saunders »

Skeptical you are in deed. I scanned all of the code (you got the same one twice in the middle btw) but concentrated on the last one, Router. Router is indeed impossible to test because it has virtually no interface to the outside world at all other than that which is retrieved from global functions and can't be mocked:

Code: Select all

public function __construct()
  {
      $this->faction = &_get_index();
      $this->config = _get_config('base');
So I'd say they are right. Use the Zend Framework.
User avatar
Jenk
DevNet Master
Posts: 3587
Joined: Mon Sep 19, 2005 6:24 am
Location: London

Post by Jenk »

You could quite easily mock those functions.. just not with SimpleTest, but the 'old fashioned' way.
Post Reply