Simpletest expectation class that ignores whitespace in Mock Zend Db Queries

I was trying out Simpletest (unit testing framework) using a mock Zend Db connection that expected a certain query to be called within the test subject class.

Mock objects are a handy solution when you want to avoid having to be using a test database for unit tests.

The trouble was the test was failing merely because of white space differences.

e.g

SELECT VERSION()

was different to

SELECT   VERSION()

so i read the tutorial on how to write your own expectations (see how to write your own expectations: http://www.simpletest.org/en/expectation_documentation.html )

and came up with this, which seems to work:

<?php

class MatchStringIgnoringWhitespaceExpectation extends EqualExpectation
	{
	function __construct($expected)
		{
		$this->expected_str = $expected;
		}

	function test($given)
		{

		$this->processed_given = trim($given);
		$this->processed_expected = trim($this->expected_str);
		//process each string to remove multiple occurrences (one of more) of 'any white space'
		$this->processed_expected = eregi_replace('[[:space:]]+',' ',$this->processed_expected);
		$this->processed_given = eregi_replace('[[:space:]]+',' ',$this->processed_given);

		if ($this->processed_given == $this->processed_expected)
			{
			return TRUE;
			}
		else	{
			return FALSE;
			}
		}

	function testMessage($given)
		{

		$str = "Match String Ignoring Whitespace: we expected [". $this->expected_str ."]
		which was processed as[". $this->processed_expected ."]
		the test gave [". $given  ."] which was processed as [".$this->processed_given."]";
		echo $str;

		}
	}

the one thing that confused me - i could not get the error message to display by following the advised technique of returning the message. Instead it seems to work if you print it.

I have not tested this in a CLI version.

Here’s an example of it in action

//making the mock Zend Adaptor

require_once('Zend/Db/Adapter/Mysqli.php');

Mock::generate('Zend_Db_Adapter_Mysqli', 'BasicMockZend_Db_Adapter_Mysqli');
class MockZend_Db_Adapter_Mysqli extends BasicMockZend_Db_Adapter_Mysqli
	{

	function __construct()
		{
		parent::__construct();
		$this->setReturnValue('query', false);
		}

	}

require_once('Zend/Db/Statement.php');
Mock::generate('Zend_Db_Statement', 'BasicMockZend_Db_Statement');
class MockZend_Db_Statement extends BasicMockZend_Db_Statement
	{
	function __construct()
		{
		parent::__construct();
		$this->setReturnValue('execute', false);
		}
	}

//include my homebrewed expectation
require_once(dirname(__FILE__) . '/simpletest_extensions/match_string_ignoring_whitespace_expectation.php');

class TestOf_DBQuery extends UnitTestCase
	{
	//....
	function testDBversioncallQuery()
          {
	  //....
	  $MockDb_obj = new MockZend_Db_Adapter_Mysqli($this);

	  //this should expect the correct query but ignore whitspace
	  $MockDb_obj->expectAt(0,'query', array(new MatchStringIgnoringWhitespaceExpectation('SELECT VERSION()')));

	//...continue test

The Mock Zend DB Adaptor object expects to receive “SELECT VERSION()” as the argument to the query() method (on the first time it is called by the tested class) .

I have not tested this in UTF-8

Just another tip

Because we have set the return value for the mock db object within its constructor, trying to set the return value later in the script will not work. This gotcha caught me for ages.

To make a mock db object return a db statement object upon a query, one should use the setReturnValueAt methods like so,

$MockStmt_obj->setReturnValue(’fetchColumn’, 1);

$MockDb_obj->setReturnValueAt(0, ‘query’,$MockStmt_obj);

The first time the query() method is called it returns the statement object. Whichhas had its fetchColumn() method mocked to return the integer 1.

This would be used in a test subject like so:

$query=’my query’;
$db_obj = $this->get_db_obj();
$result_obj = $db_obj->query($query);
if ($col_value = $result_obj->fetchColumn() > 0) {

//… do something with $col_value

Leave a Reply