Created
December 28, 2012 03:40
-
-
Save anonymous/4394246 to your computer and use it in GitHub Desktop.
Make code unit-testable
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
// Often the case | |
class User { | |
public function getCurrentUser() | |
{ | |
$user_id = $_SESSION['user_id']; | |
$user = App::db->select('user')->where('id', $user_id)->limit(1)->get(); | |
if ( $user->num_results() > 0 ) | |
{ | |
return $user->row(); | |
} | |
return FALSE; | |
} | |
} | |
/* | |
1. The above isn't testable. Command-line won't have $_SESSION available | |
2. Above depends on specific database implementation | |
*/ | |
// First, let's abstract this out to something more generic | |
class User { | |
public function getUser($user_id) | |
{ | |
$user = App::db->select('user')->where('id', $user_id)->limit(1)->get(); | |
if ( $user->num_results() > 0 ) | |
{ | |
return $user->row(); | |
} | |
return FALSE; | |
} | |
} | |
/* | |
The above can accept any user | |
*/ | |
// Next, let's start with some basic Dependency Injection | |
class User { | |
public function __construct($db_connection) | |
{ | |
$this->_db = $db_connection; | |
} | |
public function getUser($user_id) | |
{ | |
$user = $this->_db->select('user')->where('id', $user_id)->limit(1)->get(); | |
if ( $user->num_results() > 0 ) | |
{ | |
return $user->row(); | |
} | |
return FALSE; | |
} | |
} | |
/* | |
At this point, we're basically testable. We pass in the database connection and user id, so the class | |
needs no knowledge of its dependencies. We can run this in a unit test and test to see if we get results. | |
We can switch out the database connection if we're switching from MySQL to PostgreSQL, for instance. | |
We can pass in any user_id, instead of only getting the "current" user. | |
But we can do better. | |
*/ | |
// Add some further abstraction | |
interface iUserData { | |
public function getUser($user_id); | |
} | |
class MysqlUser implements iUserData { | |
public function getUser($user_id) | |
{ | |
$user = $this->_connetion->select('user')->where('id', $user_id)->limit(1)->get(); | |
if ( $user->num_results() > 0 ) | |
{ | |
return $user->row(); | |
} | |
return FALSE; | |
} | |
} | |
class User { | |
public function __construct(iUserData $userdata) | |
{ | |
$this->_db = $userdata; | |
} | |
public function getUser($user_id) | |
{ | |
return $this->_db->getUser($user_id); | |
} | |
} | |
// Usage | |
$user = new User( new MysqlUser() ); | |
$user_id = App::session('user_id'); | |
$currentUser = $user->getUser($user_id); | |
/* | |
So, what just happened? | |
*/ |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment