We all know the importance of unit testing. But to write unit testable code requires a different kind of thinking. Take this method for example: it’s a simple method that executes a SQL query:
1 2 3 4 5 6 7 8 9 10 11 |
class Database { public function select($what, $from, $where) { $result = $this->pdoInstance->query( sprintf('SELECT `%1$s` FROM `%2$s` WHERE `%3$s`;', $what, $from, $where) ); return $result; } } |
Now you could imagine that to test this code it requires setting up some actions to do before running your test suite, like dropping and re-creating your testdatabase. Also, you unit test itself must perform all kind of SQL queries to check if the result matches.
Let’s break things up
The main problem with the above method is: you don’t want to test if your database works, you want to test if your select() -method executes the correct query. Therefore we only need to check if our sprintf() -function creates the correct SQL-query. Let’s look at the following, slightly adjusted code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
class Database { public function select($what, $from, $where) { $result = $this->pdoInstance->query( $this->generateSelectSql($what, $from, $where) ); return $result; } public function generateSelectSql($what, $from, $where) { return sprintf('SELECT `%1$s` FROM `%2$s` WHERE %3$s;', $what, $from, $where); } } |
We’ve now broke up our select() -method into another generateSelectSql() -method. This is just waiting to be unit tested: it’s just a method that takes some parameters and returns a string.
Create the test
With the above class we can create the following, simple unit test:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
class DatabaseTest extends PHPUnit_Framework_TestCase { private $database; public function setUp() { require_once('/path/to/Database.php'); $this->database = new Database(); } public function testgenerateSelectSql() { $this->assertEquals( "SELECT `id` FROM `table` WHERE `foo` = \'bar\';", $this->database->generateSelectSQL('id', 'table', '`foo` = \'bar\'') ); } } |
As you can see, this test doesn’t test if the query is successfully executed, but it checks if our database-class creates the correct select-query.
In conclusion
This is of course a very simple example, but the main thing that I want to show you here is that if you want solid, testable code you need to think about how you set it all up: If you’re going to write long, complex methods that call out a lot of external sources you’re going to have a hard time testing all that code.
But if you separate your code into more logical, basic input/output-functions, writing unit tests isn’t that hard. It’s even fun! And it comes with another great advantage: your code is going to be easier to read and to maintain and debug, because your logic is separated in different parts that operate separate from each other.
So there you have it, now go out and test!
Visitors give this article an average rating of 5.0 out of 5.
How would you rate this article?
★ ★ ★ ★ ★