Prev | Next |
Example 4.1 shows how we can write tests using PHPUnit that exercice PHP's array operations. The example introduces the basic conventions and steps for writing tests with PHPUnit:
The tests for a class Class
go into a class ClassTest
.
ClassTest
inherits (most of the time) from PHPUnit_Framework_TestCase
.
The tests are public methods that are named test*
.
Alternatively, you can use the @test
annotation in a method's docblock to mark it as a test method.
Inside the test methods, assertion methods such as assertEquals()
(see the section called “PHPUnit_Framework_Assert”) are used to assert that an actual value matches an expected value.
Example 4.1: Testing array operations with PHPUnit
<?php
class StackTest extends PHPUnit_Framework_TestCase
{
public function testPushAndPop()
{
$stack = array();
$this->assertEquals(0, count($stack));
array_push($stack, 'foo');
$this->assertEquals('foo', $stack[count($stack)-1]);
$this->assertEquals(1, count($stack));
$this->assertEquals('foo', array_pop($stack));
$this->assertEquals(0, count($stack));
}
}
?>
Whenever you are tempted to type something into a
| ||
--Martin Fowler |
Unit Tests are primarily written as a good practice to help developers identify and fix bugs, to refactor code and to serve as documentation for a unit of software under test. To achieve these benefits, unit tests ideally should cover all the possible paths in a program. One unit test usually covers one specific path in one function or method. However a test method is not necessary an encapsulated, independent entity. Often there are implicit dependencies between test methods, hidden in the implementation scenario of a test. | ||
--Adrian Kuhn et. al. |
PHPUnit supports the declaration of explicit dependencies between test methods. Such dependencies do not define the order in which the test methods are to be executed but they allow the returning of an instance of the test fixture by a producer and passing it to the dependent consumers.
A producer is a test method that yields its unit under test as return value.
A consumer is a test method that depends on one or more producers and their return values.
Example 4.2 shows
how to use the @depends
annotation to express
dependencies between test methods.
Example 4.2: Using the @depends
annotation to express dependencies
<?php
class StackTest extends PHPUnit_Framework_TestCase
{
public function testEmpty()
{
$stack = array();
$this->assertEmpty($stack);
return $stack;
}
/**
* @depends testEmpty
*/
public function testPush(array $stack)
{
array_push($stack, 'foo');
$this->assertEquals('foo', $stack[count($stack)-1]);
$this->assertNotEmpty($stack);
return $stack;
}
/**
* @depends testPush
*/
public function testPop(array $stack)
{
$this->assertEquals('foo', array_pop($stack));
$this->assertEmpty($stack);
}
}
?>
In the example above, the first test, testEmpty()
,
creates a new array and asserts that it is empty. The test then returns
the fixture as its result. The second test, testPush()
,
depends on testEmpty()
and is passed the result of that
depended-upon test as its argument. Finally, testPop()
depends upons testPush()
.
To quickly localize defects, we want our attention to be focussed on relevant failing tests. This is why PHPUnit skips the execution of a test when a depended-upon test has failed. This improves defect localization by exploiting the dependencies between tests as shown in Example 4.3.
Example 4.3: Exploiting the dependencies between tests
<?php
class DependencyFailureTest extends PHPUnit_Framework_TestCase
{
public function testOne()
{
$this->assertTrue(FALSE);
}
/**
* @depends testOne
*/
public function testTwo()
{
}
}
?>
phpunit --verbose DependencyFailureTest
PHPUnit 3.5.0 by Sebastian Bergmann.
DependencyFailureTest
FS
Time: 0 seconds
There was 1 failure:
1) testOne(DependencyFailureTest)
Failed asserting that <boolean:false> is true.
/home/sb/DependencyFailureTest.php:6
There was 1 skipped test:
1) testTwo(DependencyFailureTest)
This test depends on "DependencyFailureTest::testOne" to pass.
FAILURES!
Tests: 2, Assertions: 1, Failures: 1, Skipped: 1.
A test may have more than one @depends
annotation.
PHPUnit does not change the order in which tests are executed, you have to
ensure that the dependencies of a test can actually be met before the test
is run.
A test method can accept arbitrary arguments. These arguments are to be
provided by a data provider method (provider()
in
Example 4.4).
The data provider method to be used is specified using the
@dataProvider
annotation.
A data provider method must be public
and either return
an array of arrays or an object that implements the Iterator
interface and yields an array for each iteration step. For each array that
is part of the collection the test method will be called with the contents
of the array as its arguments.
Example 4.4: Using data providers
<?php
class DataTest extends PHPUnit_Framework_TestCase
{
/**
* @dataProvider provider
*/
public function testAdd($a, $b, $c)
{
$this->assertEquals($c, $a + $b);
}
public function provider()
{
return array(
array(0, 0, 0),
array(0, 1, 1),
array(1, 0, 1),
array(1, 1, 3)
);
}
}
?>
phpunit DataTest
PHPUnit 3.5.0 by Sebastian Bergmann.
...F
Time: 0 seconds
There was 1 failure:
1) testAdd(DataTest) with data (1, 1, 3)
Failed asserting that <integer:2> matches expected value <integer:3>.
/home/sb/DataTest.php:21
FAILURES!
Tests: 4, Assertions: 4, Failures: 1.
Example 4.5
shows how to use the @expectedException
annotation to
test whether an exception is thrown inside the tested code.
Example 4.5: Using the @expectedException annotation
<?php
class ExceptionTest extends PHPUnit_Framework_TestCase
{
/**
* @expectedException InvalidArgumentException
*/
public function testException()
{
}
}
?>
phpunit ExceptionTest
PHPUnit 3.5.0 by Sebastian Bergmann.
F
Time: 0 seconds
There was 1 failure:
1) testException(ExceptionTest)
Expected exception InvalidArgumentException
FAILURES!
Tests: 1, Assertions: 1, Failures: 1.
Alternatively, you can use the setExpectedException()
method to set the expected exception as shown in Example 4.6.
Example 4.6: Expecting an exception to be raised by the tested code
<?php
class ExceptionTest extends PHPUnit_Framework_TestCase
{
public function testException()
{
$this->setExpectedException('InvalidArgumentException');
}
}
?>
phpunit ExceptionTest
PHPUnit 3.5.0 by Sebastian Bergmann.
F
Time: 0 seconds
There was 1 failure:
1) testException(ExceptionTest)
Expected exception InvalidArgumentException
FAILURES!
Tests: 1, Assertions: 1, Failures: 1.
Table 4.1 shows the methods provided for testing exceptions.
Table 4.1. Methods for testing exceptions
Method | Meaning |
---|---|
void setExpectedException(string $exceptionName) | Set the name of the expected exception to $exceptionName . |
String getExpectedException() | Return the name of the expected exception. |
You can also use the approach shown in Example 4.7 to test exceptions.
Example 4.7: Alternative approach to testing exceptions
<?php
class ExceptionTest extends PHPUnit_Framework_TestCase {
public function testException() {
try {
// ... Code that is expected to raise an exception ...
}
catch (InvalidArgumentException $expected) {
return;
}
$this->fail('An expected exception has not been raised.');
}
}
?>
If the code that is expected to raise an exception in
Example 4.7
does not raise the expected exception, the subsequent call to
fail()
(see
Table 21.2) will halt the
test and signal a problem with the test. If the expected exception is
raised, the catch
block will be executed, and the
test will end successfully.
By default, PHPUnit converts PHP errors, warnings, and notices that are triggered during the execution of a test to an exception. Using these exceptions, you can, for instance, expect a test to trigger a PHP error as shown in Example 4.8.
Example 4.8: Expecting a PHP error using @expectedException
<?php
class ExpectedErrorTest extends PHPUnit_Framework_TestCase
{
/**
* @expectedException PHPUnit_Framework_Error
*/
public function testFailingInclude()
{
include 'not_existing_file.php';
}
}
?>
phpunit ExpectedErrorTest
PHPUnit 3.5.0 by Sebastian Bergmann.
.
Time: 0 seconds
OK (1 test, 1 assertion)
PHPUnit_Framework_Error_Notice
and
PHPUnit_Framework_Error_Warning
represent PHP notices
and warnings, respectively.
Prev | Next |
assertArrayHasKey()
assertClassHasAttribute()
assertClassHasStaticAttribute()
assertContains()
assertContainsOnly()
assertEmpty()
assertEqualXMLStructure()
assertEquals()
assertFalse()
assertFileEquals()
assertFileExists()
assertGreaterThan()
assertGreaterThanOrEqual()
assertInstanceOf()
assertInternalType()
assertLessThan()
assertLessThanOrEqual()
assertNull()
assertObjectHasAttribute()
assertRegExp()
assertStringMatchesFormat()
assertStringMatchesFormatFile()
assertSame()
assertSelectCount()
assertSelectEquals()
assertSelectRegExp()
assertStringEndsWith()
assertStringEqualsFile()
assertStringStartsWith()
assertTag()
assertThat()
assertTrue()
assertType()
assertXmlFileEqualsXmlFile()
assertXmlStringEqualsXmlFile()
assertXmlStringEqualsXmlString()
Copyright © 2005-2010 Sebastian Bergmann.