PHPUnit tests do not require (much?) human judgement to interpret, and it is easy to run many of them at the same time. It is even easier to remove them from your code prior to delivery, as they are never really 'in' your code.
When you need to test something here is what you do:
For example, to test that the sum of two Moneys with the same currency contains a value which is the sum of the values of the two Moneys, write:
Class MoneyTest extends TestCase {
function test_simpleadd() { };
$test = new MoneyTest( "test_simpleAdd" ); |
If you want to write a test similar to the one you have already written, write a Fixture instead. When you want to run more than one test, create Suite.
To some extent, you can make writing the fixture code easier by paying careful attention to the constructors you write. However, a much bigger saving comes from sharing fixture code. Often, you will be able to use the same fixture for several different tests. Each case will send slightly different messages or parameters to the fixture and will check for different results.
When you have a common fixture, here is what you do:
For example, to write several test cases that want to work with different combinations of 12 Swiss Francs, 14 Swiss Francs, and 28 US Dollars, first create a fixture:
Class MoneyTest extends TestCase { var $m12CHF; var $m14CHF; var $m28USD;
function MoneyTest( $name = "MoneyTest" ) {
function setUp() {
function teardown() { |
Once you have your fixture in place, you can write as many Test Cases as you like!
For example, to test the addition of a Money and a MoneyBag, write:
Class MoneyBagTest extends TestCase { var $m12CHF; var $m14CHF; var $m28USD; var $mArray1; var $moneybag1; var $moneybag2;
function MoneyBagTest( $name = "MoneyBagTest" ) {
function setUp() {
$this->mArray1 = array();
$this->moneybag1 = new MoneyBag( $this->mArray1 );
function teardown() {
function test_simpleAdd() {
function test_bagSimpleAdd() { };
$test = new MoneyBagTest( "test_bagSimpleAdd" ); |
Once you have several tests, organize them into a Suite.
For example, to run a single test case, you execute:
$test = new MoneyBagTest( "test_bagSimpleAdd" ); $testRunner = new TestRunner(); $testRunner->run( $test ); |
To create a suite of two test cases and run them together, execute:
$test1 = new MoneyBagTest( "test_simpleAdd" ); $test2 = new MoneyBagTest( "test_bagSimpleAdd" ); $suite = new TestSuite(); $suite->addTest( $test 1); $suite->addTest( $test2 ); $testRunner = new TestRunner(); $testRunner->run( $suite ); |
Another way is to let PHPUnit extract a Suite from a TestCase. To do so you pass the name of your TestCase to the TestSuite constructor.
$suite = new TestSuite( "MoneyBagTest" ); $testRunner = new TestRunner(); $testRunner->run( $suite ); |
Use the manual way when you want a suite to only contain a subset of test cases. Otherwise the automatic suite extraction is the preferred way. It avoids you having to update the suite creation code when you add a new test case.
Test Suites don't have to contain TestCases. They can contain other TestSuites and TestCases together.
$suite1 = new TestSuite( "MoneyBagTest" ); $suite2 = new TestSuite(); $suite2->addTest( $suite1 ); $testRunner = new TestRunner(); $testRunner->run( $suite2 ); |
For ease of understanding, and simplicity of code, I will not delve too far into the alternatives other than to say, when a TestCase objects run() method is called, it returns an object of type TestResult. This object can be queried to determine the success or failure of the test executed.
To do so means accessing such methods of the TestResult such as countFailures(), but I am not going to cover there use - refer to the phpunit.php file itself if you are interested in the inner workings!
-- Additions below submitted by Paul Baranowski paulbaranowski@users.sourceforge.net --
echo "<html>"; echo "<head>"; echo "<title>PHP-Unit Results</title>"; echo "<STYLE TYPE=\"text/css\">"; echo "include(\"phpunit/stylesheet.css\")"; echo "</STYLE>"; echo "</head>"; echo "<body>";
Or put it in the constructor of PrettyTestResult:
/* Specialize TestResult to produce text/html report */ Class PrettyTestResult extends TestResult { function PrettyTestResult() { $this->TestResult(); // call superclass constructor echo "<html>"; echo "<head>"; echo "<title>PHP-Unit Results</title>"; echo "<STYLE TYPE=\"text/css\">"; echo "include(\"phpunit/stylesheet.css\")"; echo "</STYLE>"; echo "</head>"; echo "<body>"; echo "<h2>Tests</h2>"; echo "<TABLE CELLSPACING=\"1\" CELLPADDING=\"1\" BORDER=\"0\" WIDTH=\"90%\" ALIGN=\"CENTER\" class=\"details\">"; echo "<TR><TH>Class</TH><TH>Function</TH><TH>Success?</TH></TR>"; } ... };
How to Assert Yourself
There are many ways to check for errors in PHP-Unit:
assert($booleanFailOnTrue, $optionalMessage)assertEquals($expected, $actual, $message=0)
An error will be thrown if the first two values given are NOT equal.
assertRegexp($regexp, $actual, $message=false)
An error will be thrown if the regular expression does not match the second argument.
assertEqualsMultilineStrings($string0, $string1, $message="")
An error will be thrown if the two strings do not match.
You can also do your own "if" test, and if it fails call $this->fail("message").
DB::connect ("mysql://root:@localhost/MyDatabaseName"); if (DB::isError($connection)) { $this->fail($connection->errorMessage()); }
Testing Style
Put underscores between words for your function names. PHP-Unit will display the test names in lowercase even if the function name is declared with uppercase characters in them. Thus underscores are much more readable. Thus you should do this:
function test_database_access()Instead of:
function testDatabaseAccess()Because the latter will be printed as:
testdatabaseaccess