A pretty popular myth about avoiding global state (singletons, multitons, registries, global variable, static variables/methods) is that it results in creating widely used objects more often than needed. The most common example in this case is a database connection. We try to avoid global state to let objects express their dependencies clearly: the object constructor should be as readable as “give me this, give me that and I will work”. Let’s talk about a situation where we instanciate a relatively complex set of domain objects including a service layer. For the example, we assume that we read an existing customer. We use the CustomerServiceLayer to retrieve the Customer, which uses the CustomerRepository to create the Customer object which needs a DatabaseConnection connection and passes a strategy (NameFormattingStrategy) to format the name of the customer to the Customer object and a CustomerDataMapper to allow the Customer object to save itself. Here are the constructor signatures of the involved components:
class Customer ...
public function __construct(
NameFormattingStrategy $nameFormattingStrategy
)
class CustomerRepository ...
public function __construct(
DatabaseConnection $connection,
CustomerDataMapper $dataMapper,
NameFormattingStrategy $nameFormattingStrategy
)
class CustomerServiceLayer ...
public function __construct(CustomerRepository $repository)
class CustomerDataMapper ...
public function __construct(DatabaseConnection $connection)
class DatabaseConnection ...
public function __construct(
string $host,
int $port,
string $username,
string $password,
string $database
)
So, all we do in the page controller, may it be a (page) controller or a plain PHP file is instanciating the service layer and its dependencies:
$databaseConnection = new DatabaseConnection(...);
$customerDataMapper = new CustomerDataMapper($databaseConnection);
$nameFormattingStrategy = new NameFormattingStrategy();
$customerRepository = new CustomerRepository(
$databaseConnection,
$customerDataMapper,
$nameFormattingStrategy
);
$serviceLayer = new CustomerServiceLayer($customerRepository);
$customer = $serviceLayer->getCustomerById((int)$_GET['customer_id]);
... pass it to the view, do nifty things ...
If other components, like the OrderRepository needs a database connection, just pass it to it. No need to let the order repository know how to get it. It is just there. In your unit test you can passed a mocked repository, a mocked database connection and a mocked data mapper depending on what particular part of the chain you are going to test. By the way: the heavy construction work could be easily passed to a number of factories just responsible for creating your objects. These factories are easily testable too as the only assertion made would be is the returned object correctly configured.
Filed under OOD, OOP, PHP, Unit testing & eleven comments & no trackbacks
setExpectedException will trigger a transparent error, while a typo in expectedException will lead to Obscure Test, and most likely a Mistery Guest.Filed under PHP, PHPUnit, Unit testing, xUnit & six comments & no trackbacks
As I previously mentioned we made some effort to better check exceptions. The target is not only ensuring that a various exception is thrown but also that this exception is really the one which is expected. The result was a patch for PHPUnit to test for the exception message (which is already in) and the exception code. As Sebastian mentioned in the PHPUnit 3.2.9 release announcement, the latter is now included too. Therefore a few new options are available.
Example will fail:
<?php
public function testException()
{
$this->setExpectedException('Exception', 'Exception message', 100);
throw new Exception('Invalid message', 10);
}
Example will pass:
<?php
public function testException()
{
$this->setExpectedException('Exception', 'Exception message', 100);
throw new Exception('Exception message', 100);
}
Specifying exception tests with the annotations syntax:
<?php
/**
* @expectedException Exception error message 100
*/
public function testException()
{
throw new Exception('error message', 100);
}
Another attractive new feature is the option to use namespaces as a test organization separators. Until now, the PEAR scheme was used for PHPUnit test (_ becomes the directory separator, .php is auto-attached). This means a test was called My_ObjectTest and was supposed to be located in My/ObjectTest.php. Thanks to a really simple patch the test location stays the same, while the class name might be changed to My::ObjectTest. Happy namespacing.
Filed under PHP, PHPUnit, Unit testing & five comments & no trackbacks
Since PHPUnit 3.2.0 the former extension for exception test case (PHPUnit_Extension_ExceptionTest) has been merged back into the default test case. This allows you to use setExpextedException() in a normal test case. A simple exception test looks like that:
<?php
class MyTest extends PHPUnit_Framework_TestCase
{
public function testException()
{
$this->setExpectedException('Exception');
throw new Exception();
}
/**
* @expectedException Exception
*/
public function testException2()
{
throw new Exception()
}
}
Often this is not enough. When you use a Zend Framework alike style for exceptions (one base class to rule them all) you often throw the same exception class with different messages. To test wheither the correct exception has been thrown, I discussed with Sebastian Bergmann about introducing an contains assertion for messages and this patch was applied. So in the current PHPUnit trunk you can test exception messages:
<?php
class MyTest extends PHPUnit_Framework_TestCase
{
public function testException()
{
$this->setExpectedException('Exception', 'Exception message');
throw new Exception('Exception message');
}
/**
* @expectedException Exception Exception message
*/
public function testException2()
{
throw new Exception('Exception message')
}
}
As internally PHPUnit uses an assertContains for the exception message you can even test for incomplete strings like an exception message containing a random file name.
I proposed to do the same for exception codes but Sebastian did not agree. But let’s see, maybe that will change when Zend Framework is going to use exception codes a lot.
Filed under PHP, PHPUnit, Unit testing & five comments & one trackback
PHPUnit provides a filter util to mark a piece of code as test fixture. This makes the template disappear from the coverage report and helps a lot to keep the code coverage report readable and clean. In case of Smarty you just use the builtin php-tag to execute native PHP calls:
{php}PHPUnit_Util_Filter::addFileToFilter(__FILE__, 'TESTS');{/php}
Filed under PHP, PHPUnit, Smarty, Unit testing & no comments & no trackbacks
Since I setting up a preliminary unitesting server is on my todo list for the next time at work I’ve looking at CruiseControl for continuous integration to decide wheither this is worth utilizing or not. I found it a bit unhandy to integrate it in a PHP environment (we are using Zend Framework, PHPUnit and phing to name a few). Today I read about Xinc on Sebastian Bergmanns weblog (thanks by the way: it is a pleasure to work with PHPUnit every day). Maybe this is the tool I was looking for. I will evaluate (and blog about) the current state and if it is already usable.
Filed under Continuous integration, PHP, PHPUnit, Unit testing & no comments & no trackbacks
If you are interested in using Phing and PHPUnit >=3.0 together, you can just use this patch. It is heavily based on this work by Kentaro Ishitoya.
Filed under Build system, Code, Phing, PHP, PHPUnit, Technology, Unit testing & one comment & no trackbacks