Licensed under Creative Commons Attribution 3.0 (cc)
Created by: Jens Roland, 2010 (mail@jensroland.com)
Credits to: t'mo & redguy from the CodeIgniter Forums
I had been looking for a unit testing suite for CodeIgniter that's a little more JUnit-like than the one included in CI.
My criteria were:
assert_*()
functions)After searching the forums for a while, I came across a brilliant unit testing solution by t'mo and a class of assert functions by redguy. By simply combining these, I had (1), (2) and (3) solved already. It took a bit more work, and more than a little magic, to meet all five criteria, but here it is.
Enjoy!
The entire testing suite consists of just two controllers, three views, and an example class ;)
Toast.php
Toast_all.php
header.php
results.php
<li></li>
elementsfooter.php
example_tests.php
/app/controllers/test
/app/views/test
None.
That's right. Fucking NONE! Released means stable, motherfuckers! Take *that*, perpetual-beta-web-2.0-wussies! </rant></profanity>
Ahem. Anyway, if you *do* find a bug (and there's ALWAYS another bug), or if you make an improvement to the test suite, or just want to send a shoutout to a guy who codes when he's drunk, feel free to drop me an email.
Simply subclass the Toast file and write your tests as functions with the prefix 'test_':
require_once(APPPATH . '/controllers/test/Toast.php');
class My_test_class extends Toast
{
function My_test_class()
{
parent::Toast(__FILE__); // Remember this
}
function test_some_action()
{
// Test code goes here
$my_var = 2 + 2;
$this->_assert_equals($my_var, 4);
}
function test_some_other_action()
{
// Test code goes here
$my_var = true;
$this->_assert_false($my_var);
}
}
Place your test classes INSIDE the /test/
folder (Toast_all can't find them otherwise), and you're ready to rock 'n' roll.
To run all the tests in a test class, simply point your browser to the class name:
http://www.example.com/test/my_test_class
To run an individual test, point your browser to the test function, WITHOUT the 'test_' prefix:
http://www.example.com/test/my_test_class/some_action
And to run all the tests classes in the /test/
folder at once, point your browser to the Toast_all controller:
http://www.example.com/test/toast_all
That's all! If you need more flexibility, check the feature list below, but there's really not much more to it. All the dirty work is handled behind the scenes.
You can use multiple asserts within the same function; if any one of them fails, the test fails. The assert functions available are (remember to call them using $this->
):
_assert_true()
_assert_false()
_assert_equals()
_assert_not_equals()
_assert_empty()
_assert_not_empty()
Plus the strict (===
) versions:
_assert_true_strict()
_assert_false_strict()
_assert_equals_strict()
_assert_not_equals_strict()
After evaluating the input, each assert function returns the result of its evaluation, in case you want to use it for branching or conditionals inside the test function. Though, if you don't need that level of fanciness, you can just run the asserts you need and let Toast handle the rest.
Also available are the following two optional cleanup functions. If defined in a test class, they are automatically called when the individual tests are run:
_pre()
_post()
Simply override these functions in your test classes if you need to do some housekeeping before and/or after each tests (like adding/removing test data in the database, performing logins, re-instantiating classes, clearing memory, etc.)
If you need to echo a debug message while you're unit testing, simply use the message
variable:
$this->message = 'if this test case fails, blame it on my_var: ' . $my_var;
(Of course you're using a decent debugger so you never actually need to echo debug data like that.. but let's pretend you weren't)
Any value you assign to the message variable is automatically embedded in the test result page next to the test in which it was assigned.
In some cases, it is useful to force a test to fail. Instead of using the classic but slightly cryptic _assert_true(FALSE)
method, you can just call the _fail
function:
$this->_fail();
You can even include an error message which will be embedded in the test result page next to the test:
$this->_fail('Deprecated code should not be called');
Note that the error message will override the $this->message
variable (for now).
Toast uses CodeIgniter's built-in benchmarking class to calculate how long it takes for the tests to run. This is all handled automatically by CI and displayed in footer.php.
Why would you need benchmarking in a unit testing suite? Well, one of the big advantages of unit testing is that it enables you to do massive refactoring of your base classes without worrying about hidden side effects. And I find that whenever I've completed a round of refactoring of my central classes, I really want to know how it's affected my site's performance. The benchmarking numbers come in handy for just that.
Of course, they are no substitute for proper profiling of your functions and controllers, but if your test coverage is good, they can help you catch most major performance screwups.
Because of the way Toast parses test functions, the following function names are reserved and can not be used / overridden in the test classes:
index
show_results
test_index
test_show_results
test__* (double underscores)
_get_test_methods
_remap
_run
_run_all
_show
_show_all
_fail
You may override the '_assert_*'
functions all you want, but that shouldn't be necessary.
- Version 1.5
- Minor cosmetic changes
Added missing functions_assert_true_strict
and_assert_false_strict
as well as the_fail
function (thanks to Chris from oedo.net)- Version 1.4
- Removed all PHP shorttags from the views (thanks to Andree Surya)
Removed shorttag requirement in README file
Tightened up some language in the README file- Version 1.3
- Added support for CI's language packs
Added shorttag requirement in README file- Version 1.2
- Fixed some typos and cleaned up the README file
- Version 1.1
- Added links to results pages
Now uses site_url() as CI recommends
Added changelog
Minor cosmetic changes- Version 1.0
- Initial release