Skip to content

Instantly share code, notes, and snippets.

@craigjbass
Last active December 26, 2015 17:39
Show Gist options
  • Select an option

  • Save craigjbass/7188526 to your computer and use it in GitHub Desktop.

Select an option

Save craigjbass/7188526 to your computer and use it in GitHub Desktop.
"Monadic" Models for improved unit-testability. (Pure - Impure separation of control)
<?php
class ImpureDatabaseWrapper {
private $sql;
private $pureBinding;
/**
* @var \Zend_Db_Select $sql
* @var \Closure $pureBinding (Closure that contains "pure" code - i.e. it doesn't cause any side-effects!)
*/
public function __construct( \Zend_Db_Select $sql, \Closure $pureBinding )
{
$this->sql = $sql;
$this->pureBinding = $pureBinding
}
/**
* @return mixed
*/
public function get()
{
$result = $sql->query()->fetchAll()
$closure = $this->pureBinding;
return $closure( $result );
}
/**
* Call this in unit tests
*
* @return \Closure
*/
public function getBinding()
{
return $this->pureBinding
}
}
<?php
class Model_SomeDatabase {
public function retrieveName( $id ) {
/* Assume ::getInstance is a factory method for a Zend_Db_Table concrete class */
/* @var $table \Zend_Db_Table_Abstract */
$table = Table::getInstance()
$select = $table->select();
$select->where('id = ?', $id);
return new ImpureDatabaseWrapper( $select, function( $result ) {
//Naive example (but assume complex manipulation here)
return $result['first_name'] . ' ' . $result['last_name']
} );
}
}
<?php
class TestSomeDatabase extends PHPUnit_TestCase {
public function testRetrieveName() {
//We don't need to test Zend_Db, but we do want to test that the names are concatentated correctly
$model = new Model_SomeDatabase();
$pureLogic = $model->retrieveName()->getBinding();
$array = array(
'first_name' => 'a',
'last_name' => 'b'
);
/* This is a naive test, but assume that this is testing some really complex pure manipulation is correct */
$this->assertEqual( 'a b', $pureLogic( $array ) );
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment