Page 1 of 1
[solved]PHP Unit Testing
Posted: Thu Dec 09, 2004 5:59 am
by thomas777neo
Could somebody please show me a simple example of how to use the unit testing functionality:
e.g. Here is a simple function, how do I test it using the PHPUnit stuff.
Code: Select all
<?php
//class.render.php
class render
{
function renderText($renderString)
{
echo $renderString."<br>";
$rendered = "true";
return($rendered);
}
}
$render = new render;
?>
Code: Select all
<?php
//render.php
require("class.render.php");
$checkRender = $render-> renderText("This is a string");
if ($checkRender == "true")
{
echo "Text Rendered:".$checkRender."<br>";
}
?>
The documentation on the stuff is terrible on the web, they really complicate things. All I need is a really extremely simple example.
(With a reference to the classes that I need to use, I downloaded a few PHP Unit examples with the test class and the tested class from source fourge etc)
This would be much appreciated...I wish that simplicity could become the cornerstone of new concepts and ideas. Thanks

Re: PHP Unit Testing
Posted: Thu Dec 09, 2004 6:53 am
by xside
Code: Select all
<?php
class Render {
function renderText($renderString)
{
echo $renderString . "<br>";
$rendered = 0;
return($rendered);
}
}
require_once 'PHPUnit.php';
class Tests_Render extends PHPUnit_TestCase {
/**
* constructor
**/
function Tests_Render($name){
$this->PHPUnit_TestCase($name);
}
/**
* Called before the test functions will be executed this function is defined in PHPUnit_TestCase and overwritten here
* @access protected
*/
function setUp(){
$this->render = new Render();
}
/**
* Called after the test functions are executed this function is defined in PHPUnit_TestCase and overwritten here
* @access protected
*/
function tearDown(){
unset($this->render);
}
/**
* test the renderText function
**/
function testrenderText(){
ob_start();
$bool = $this->render->renderText("test");
$str = ob_get_contents();
ob_end_clean();
$this->assertTrue($bool, "not true returned");// error
$this->assertContains("<br>", $str);
$this->assertNotContains("<br>", $str); // error
}
}
$suite = new PHPUnit_TestSuite("Tests_Render");
$result = PHPUnit::run($suite);
echo $result->toHTML();
?>
PHPedit generate the testSuite by itself.
thomas777neo wrote:Could somebody please show me a simple example of how to use the unit testing functionality:
e.g. Here is a simple function, how do I test it using the PHPUnit stuff.
Code: Select all
<?php
//class.render.php
class render
{
function renderText($renderString)
{
echo $renderString."<br>";
$rendered = "true";
return($rendered);
}
}
$render = new render;
?>
Code: Select all
<?php
//render.php
require("class.render.php");
$checkRender = $render-> renderText("This is a string");
if ($checkRender == "true")
{
echo "Text Rendered:".$checkRender."<br>";
}
?>
The documentation on the stuff is terrible on the web, they really complicate things. All I need is a really extremely simple example.
(With a reference to the classes that I need to use, I downloaded a few PHP Unit examples with the test class and the tested class from source fourge etc)
This would be much appreciated...I wish that simplicity could become the cornerstone of new concepts and ideas. Thanks

Posted: Thu Dec 09, 2004 2:45 pm
by McGruff
I haven't used PhpUnit. AFAIK SimpleTest (link below) is the only unit testing framework with mock objects. IMO you really, really want to have mocks even if just to find out if you are a
mockist or a stubist. Mock techniques are still subject of much discussion & evaluation. Personally, my preference is for mocks.
If you do take a look at SimpleTest the docs provide a decent introduction and I'd be glad to run through a few tests for some of your classes.
Testing is the best thing you will ever learn.
Posted: Fri Dec 10, 2004 1:10 am
by thomas777neo
Thanks xside for your input. McGruff, could you please take my example then and use the simple test on it. I wonder though, how these tests handle if statements etc. Thanks for the reference, I am still busy reading the documentation. Then I would be able to clearly see which one it easier to use.
Thanks Guys
Posted: Fri Dec 10, 2004 3:37 pm
by McGruff
I found a link for a PhpUnit tutorial:
http://www.phppatterns.com/index.php/ar ... ew/33/1/2/.
For SimpleTest (note I haven't run this through the parser):
Code: Select all
###runner code
require_once('path/to/config.php'); // define SIMPLE_TEST & anything else you need for tests here
require_once(SIMPLE_TEST . 'unit_tester.php');
require_once(SIMPLE_TEST . 'reporter.php');
###
require_once('path_to/Render.php');
class TestOfRender extends UnitTestCase
{
function TestOfRender()
{
$this->UnitTestCase();
}
function testRenderText()
{
$string = 'foo';
$render =& new Render;
ob_start();
$this->assertIdentical($render->renderText($string), true);
$this->assertEqual(ob_get_contents(), $string . '<br />');
ob_end_clean();
}
}
###runner code
$test =& new TestOfRender();
$test->run(new HtmlReporter());
###
Careful with assertIdentical() and assertEqual() - latter doesn't check type. I didn't actually need to use assertIdentical() here. That's actually an important testing mistake worth mentioning: never test for anything more than you really need. If you do, alternative implementations which satisfy all the real requirements might fail the test and that hampers progress when you are refactoring.
The runner code doesn't usually go in the test. The reason for this is that you will want to group tests: an "all tests" group which runs everything, maybe various smaller groups, and finally something which runs a single test itself. When you're working on a new class, you'd be striving for the green bar with the single test. Then, when it's working, you'd run "all tests" to make sure it isn't breaking anything else. If you had to run them all individually (there could be hundreds) you wouldn't do it very often - if at all - but if you can easily run all tests each time you've edited a class you will.
With frequent "all tests" runs, you can quickly spot class interaction problems while they are still relatively easy to fix. If you waited a month between checks, there could be all kinds of bugs reinforcing and obscuring each other. The same holds true on a smaller scale, in individual tests. If you are editing a class, run its test regularly after every minor edit to check it hasn't been broken. Tests are a wonderful way to keep you on the straight and narrow and can save a lot of time spent in debugging hell.
You'll also find that they lead you to think more carefully about the behaviour of the class you're working on resulting in more robust code.
http://www.martinfowler.com/articles/co ... ation.html
Posted: Fri Dec 10, 2004 10:59 pm
by Selkirk
Simple test has great documentation and excellent support. I highly recommend it.
Re: PHP Unit Testing
Posted: Sat Dec 11, 2004 10:02 pm
by lastcraft
Hi...
xside wrote:Code: Select all
function tearDown(){
unset($this->render);
}
You don't actually need to unset this variable for PHPUnit2 as it more closely follows JUnit. Junit reinstantiates the class for each test method. The logic for this is that tests ar completely independent.
This behaviour was so surprising if you weren't in the know that I actually dropped it for SimpleTest (as does NUnit). SimpleTest instantiates the test class class just once (possibly twice with certain interfaces), usually when it's ready to run. It means also that constructors (and destructors in PHP5) can be used to do set up and tear down for the whole test case. In SimpleTest you might want to have your tear down, although it's pretty unnecessary.
SimpleTest and PHPUnit are almost identical in other respects and you can pretty much interchange the basic tutorials. PHPUnit follows JUnit more closely, but SimpleTest requires a little less setup code. You don't need the constructor chain for example and the SIMPLE_TEST constant is now deprecated. The real difference is in the extras. PHPUnit has test coverage tools. SimpleTest has mock objects and a web tester. I suspect the choice of features has something to do with PHPUnit's close association with PEAR.
I am not sure about the timing of the output buffering in the above example. SimpleTest dispatches it's errors immediately, rather than building a report. This means that the test display could get captured by the output buffering. Again this behaviour is deliberate as this way you can intersperse debug statements with the test statements. I suspect something like...
Code: Select all
class TestOfRender extends UnitTestCase {
function testRenderText() {
ob_start();
$render =& new Render();
$is_success = $render->renderText('foo');
$page = ob_get_contents();
ob_end_clean();
$this->assertIdentical($is_success, true);
$this->assertEqual($page, 'foo<br />');
}
}
...although I haven't run this either, so mine's almost certainly wrong too.
yours, Marcus
Posted: Sun Dec 12, 2004 6:09 pm
by McGruff
Both seem to work - but I think Marcus' version, with all the buffering out of the way before the assert, is better (naturally..!).
Let me know how you get on.
PS: here's another very simple example just to get familiar with some of the SimpleTest method calls. It's not a real test of course, but it does show some type behaviour and maybe gives you an idea of how tests can become a source of documentation. Written docs usually lag behind code development but tests never lie.
Code: Select all
class MyClass
{
}
class TestOfMyClass extends UnitTestCase
{
function TestOfMyClass()
{
$this->UnitTestCase();
}
function test1()
{
$this->assertTrue(true);
$this->assertEqual(true, true);
$this->assertIdentical(true, true);
$this->assertTrue(1);
$this->assertEqual(1, true);
$this->assertIdentical(1, true); // fails
$this->assertTrue('foo');
$this->assertEqual('foo', true);
$this->assertIdentical('foo', true); // fails
$this->assertTrue(array(1));
$this->assertEqual(array(1), true);
$this->assertIdentical(array(1), true); // fails
}
function test2()
{
$this->assertFalse(false);
$this->assertEqual(false, false);
$this->assertIdentical(false, false);
$this->assertFalse(0);
$this->assertEqual(0, false);
$this->assertIdentical(0, false); // fails
$this->assertFalse(null);
$this->assertEqual(null, false);
$this->assertIdentical(null, false); // fails
$this->assertFalse(array());
$this->assertEqual(array(), false);
$this->assertIdentical(array(), false); // fails
$this->assertFalse('');
$this->assertEqual('', false);
$this->assertIdentical('', false); // fails
}
}
Thanks All
Posted: Tue Dec 14, 2004 2:41 am
by thomas777neo
Hi, thank you for your valuable input. It is much appreciated. I finally did my first test yeah (sigh of relief).
Here is my code (basically a copy, paste and modify) with some extra comments. I just wanted to see if I understand the whole thing.
Code: Select all
<?php
// Require Testing Utilities and Class to be tested
require_once("unit_tester.php");
require_once("reporter.php");
require_once("class.render.php");
class TestOfRender extends UnitTestCase
{
function TestOfRender() // Constructor
{
$this->UnitTestCase();
} //function TestOfRender()
function testRenderText()
{
/*
1. Test that the parameter sent is string.
2. Test that the string ends with a <br>.
3. Test the returned value of true.
*/
//This function will turn output buffering on
ob_start();
// create new instance of render class to be tested
$render =& new render();
// Reconstruct Scenario with dummy string
$is_success = $render->renderText('foo');
//This will return the contents of the output buffer or FALSE, if output buffering isn't active.
$page = ob_get_contents();
//This function discards the contents of the output buffer and turns off output buffering.
ob_end_clean();
//assertIdentical($x, $y) Fail if $x == $y is false or a type mismatch
$this->assertIdentical($is_success, true);
//assertEqual($x, $y) Fail if $x == $y is false
$this->assertEqual($page, 'foo<br>');
} //function testRenderText()
} //class TestOfRender extends UnitTestCase
$test =& new TestOfRender();
$test->run(new HtmlReporter());
?>
Thanks Guys, this returned :
testofrender
1/1 test cases complete: 2 passes, 0 fails and 0 exceptions.
Posted: Tue Dec 14, 2004 4:38 pm
by McGruff
You got it. It really is quite simple to use once you get familiar with the set up. That green bar is a beautiful sight
Each test method name must start with "test" eg "testFoo", "testValidate" etc. As always, it helps if names are self-explanatory eg "testValidateWithInvalidArray".
Each test sets up the conditions for the test and finishes with some kind of assertion, tally() or so on. Testing creates an inductive "proof" that the class does what you think it should. Just how many tests you need is a matter of judgement. In mathematics, you might prove an algorithm is true with special cases 0 and 1, prove it for 2 and then claim (by induction) that it must be true for all higher numbers. Testing a class is similar: write tests for the special cases, one or two "representative" cases and then you're done. You can always add more tests later if you missed something. It depends on the class itself just how easy it is to test and what you need to do. Lean & mean classes which do just one thing are easier to test.