Agile Zone is brought to you in partnership with:

I am a programmer and architect (the kind that writes code) with a focus on testing and open source; I maintain the PHPUnit_Selenium project. I believe programming is one of the hardest and most beautiful jobs in the world. Giorgio is a DZone MVB and is not an employee of DZone and has posted 638 posts at DZone. You can read more from them at their website. View Full User Profile

Practical PHP Testing Patterns: Implicit Setup

01.05.2011
| 4605 views |
  • submit to reddit

Sometimes a fixture is well-defined, and can be extracted from Test Methods without loss of clarity. Maybe it's only an irrelevant part of all the fixtures we'll need in a test. Or it is a System Under Test which is a leaf in the object graph, and its instantiation is simple a new call.

We can even go as far as extracting a SUT tested in isolation, in which stubs or mocks have to be placed.

The solution to avoid repeating the creation in different Test Methods, and even to avoid repeating calls to Creation Methods, is to build the fixture in the setUp() method of your Testcase Class.

This hook method will be called automatically by PHPUnit prior to executing each of the Test Method, and since each Test Method will be called on a brand new Testcase Object, setUp() will always start from a clean scenario.

What should go in setUp()?

Meszaros uses the phrase essential but irrelevant to describe the logic that can go in a setUp() method. This mindset tries to ensure that the fixture is as much Minimal as possible (tailored to the needs of each test). You don't need to pull all the creation code in the setUp(), but only the bits which are shared across more than 90% of the tests of the class.

For example, plumbing code like infrastructure services (in integration tests) or the creation of the System Under Test itself may go in the setUp() method. You'll see more examples in the final code sample of this article. The input for the SUT instead varies widely between tests and is a good candidate for the other fixture setup patterns.

The alternatives are Inline Setup (creating fixtures in the Test Methods themselves) and Delegated Setup (extracting creation logic into Creation Methods which are not called automatically, but in the Test Method on a as-needed basis).

Implementation

The setUp() method commonly builds a Fresh Fixture, but it can pull a shared resource in order to provide references to a Shared Fixture. You can also use the hook setUpBeforeClass(), a static method for defining fixtures shared thorughout all the Test Methods in the same Testcase Class.

Symmetrically, there are the two methods teardown() and teardownAfterClass() which are hooks for defining fixture destruction code (but if the fixture is only an object graph on $this, it will be garbage collected anyway.)

In fact, you can use $this to hold references from the setUp() to the test*() method. $this will be thrown away at the end of the current test, and a new object will be created.

The virtue of this pattern is that it effectively removes the N calls to Creation Methods, saving at least one line of code from each test. However it can lead you to obscure tests where the fixture is unclear, especially if abused by pulling in setUp() the creation of objects which not all the Test Methods depends on.

However, you can always create another class to hold tests that use a different fixture. You'll lose the one-class-one-testcase-class mapping with this choice.

Examples

The code sample shows you two Testcase Classes where the setUp() method is used to create a SUT. Some code can be pulled into setUp() even when mocks are present (the wiring), while other code, such as the expectations definition, should definitely go into the tests.

<?php
class ImplicitSetupTest extends PHPUnit_Framework_TestCase
{
/**
* No need for a scope larger than private.
*/
private $arrayObject;

/**
* This SUT will be used throughout all the methods, so we can create it
* here. However I won't go as far as putting data in it already, since
* it may result in unclear tests and because some tests won't need it at all.
*/
public function setUp()
{
$this->arrayObject = new ArrayObject();
}

public function testImplementsArrayAccess()
{
$this->assertTrue($this->arrayObject instanceof ArrayAccess);

$this->arrayObject[0] = 42;
$this->assertEquals(42, $this->arrayObject[0]);
}

public function testImplementsCountable()
{
$this->assertTrue($this->arrayObject instanceof Countable);

$this->arrayObject[0] = 42;
$this->arrayObject[1] = 43;
$this->assertEquals(2, count($this->arrayObject));
}
}
<?php
class ImplicitSetupWithMocksTest extends PHPUnit_Framework_TestCase
{
private $firstIterator;
private $secondIterator;

/**
* Two Iterator composed by an AppendIterator.
* The purpose of this example is showing wiring of mocks and stubs
* to the SUT, which may take place as Implicit Setup.
*/
public function setUp()
{
$this->firstIterator = $this->getMock('Iterator');
$this->secondIterator = $this->getMock('Iterator');
$this->appendIterator = new AppendIterator();
$this->appendIterator->append($this->firstIterator);
$this->appendIterator->append($this->secondIterator);
}

public function testAppendedIteratorCanBeEmpty()
{
// defining expectations: these would never go in a setUp() method
$this->firstIterator->expects($this->any())
->method('valid')
->will($this->returnValue(false));

// the first iterator should be skipped
// ...
}

/**
* @expectedException OutOfBoundsException
*/
public function testExceptionsFromTheAppendedIteratorsBubbleUp()
{
// defining expectations: these would never go in a setUp() method
$this->firstIterator->expects($this->any())
->method('rewind')
->will($this->throwException(new OutOfBoundsException));

// call $this->appendIterator...
}

}
Published at DZone with permission of Giorgio Sironi, author and DZone MVB.

(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)