Sebastian Bergmann »
23 July 2010 »
in Presentations »
I have been invited to attend the 5th Annual Google Test Automation Conference, better known as GTAC, in Hyderabad, India in October. I am very much looking forward to discuss cutting edge challenges in test automation and evaluate potential solutions, especially with this year's focus on testability.
Another thing I like about this year's GTAC is that the participants are responsible for selecting the presentations for the conference. Here is my submission:
Challenges in Unit Testing PHP Applications
According to TIOBE, PHP is the most popular programming language after C/C++ and Java. The language has made strong inroads into large-scale, business-critical Web systems. In the six years since the release of PHP 5 -- which not only kickstarted the development of PHP-based frameworks for Web development but also the development of tools for dynamic and static testing techniques -- the PHP community as a whole has developed an increasing interest in developing software that delivers the best possible quality.
When PHP developers start to write unit tests they rarely find themselves without any constraints that are imposed by prior work of less than optimal quality. It is a well-known fact that writing unit tests for legacy code is hard. In the case of PHP it can be even harder: the legacy code has not only been written without testability in mind, but it may have been written for earlier versions of PHP that encouraged practices that make the code next to impossible to unit test.
PHPUnit, the de-facto standard framework for unit-testing PHP code, has some unique features not found in other xUnit test frameworks that allow the testing of untestable code. While developers should not use these features (as they are not required when writing tests for testable code), these features ease the pain of writing tests for legacy code and thus help developers get started with unit testing before they refactor the code for testability.
This session, presented by the creator of PHPUnit, highlights the challenges developers are facing when unit testing legacy PHP code. Some of these challenges will be familiar to developers that use other programming languages such as Java but they will see a new perspective on the problem and different approaches to solve it.
Although I am hoping, of course, that my submission will be accepted by my peers, I know that GTAC will be valuable for me even if I do not get to present: the "hallway track" of GTAC 2008 was amazing.
Sebastian Bergmann »
23 July 2010 »
in Articles »
When you look at the list of changes for PHPUnit 3.5, you will see that many of them deal with refactoring to components. Here is an overview of these new components:
- PHP_CodeCoverage
The collection, processing, and rendering of code coverage information has been factored out into a separate component. A bit more information can be found here.
- PHPUnit_MockObject
The functionality to automatically generate an object that can act as a test double for a specified original class has been factored out into a separate component. Do not worry, getMock() and related methods will work just as they did in previous versions of PHPUnit. The refactoring, however, makes the usage of other mock object libraries (such as Mockery or Phake, for instance) easier.
- DbUnit
The database testing functionality that is provided by the DbUnit extension and the respective DatabaseTestCase class has been moved to a separate component. Michael Lively Jr, the author of DbUnit, is now able to make releases of the database testing extension on a release schedule that is separate from PHPUnit itself, meaning that I will be even less involved in its development than I have before.
- PHPUnit_Selenium
SeleniumTestCase, the Selenium RC integration for PHPUnit, has been moved to a separate component to allow a release cycle separate from PHPUnit itself.
- File_Iterator, PHP_Timer, Text_Template
Utility methods to collect files and report resource usage as well as a simple templating mechanism have been moved to separate components so that they can be reused by other tools such as phpcb, phpcs, phpcpd, and pdepend.
Defined tags for this entry:
phpunit
Sebastian Bergmann »
08 June 2010 »
in Announcements »
To celebrate the 15th birthday of PHP, I have released PHPUnit 3.5 Beta 1 today. The refactoring towards components is a "new feature" that is already visible upon installation:
sb@vmware ~ % pear install phpunit/PHPUnit-beta
phpunit/PHPUnit can optionally use PHP extension "dbus"
downloading PHPUnit-3.5.0beta1.tgz ...
Starting to download PHPUnit-3.5.0beta1.tgz (105,588 bytes)
........................done: 105,588 bytes
downloading DbUnit-1.0.0beta1.tgz ...
Starting to download DbUnit-1.0.0beta1.tgz (38,209 bytes)
...done: 38,209 bytes
downloading File_Iterator-1.2.1.tgz ...
Starting to download File_Iterator-1.2.1.tgz (3,225 bytes)
...done: 3,225 bytes
downloading Text_Template-1.0.0.tgz ...
Starting to download Text_Template-1.0.0.tgz (2,493 bytes)
...done: 2,493 bytes
downloading PHP_CodeCoverage-1.0.0beta1.tgz ...
Starting to download PHP_CodeCoverage-1.0.0beta1.tgz (108,640 bytes)
...done: 108,640 bytes
downloading PHP_Timer-1.0.0.tgz ...
Starting to download PHP_Timer-1.0.0.tgz (2,536 bytes)
...done: 2,536 bytes
downloading PHPUnit_MockObject-1.0.0beta1.tgz ...
Starting to download PHPUnit_MockObject-1.0.0beta1.tgz (15,816 bytes)
...done: 15,816 bytes
downloading PHPUnit_Selenium-1.0.0beta1.tgz ...
Starting to download PHPUnit_Selenium-1.0.0beta1.tgz (15,298 bytes)
...done: 15,298 bytes
downloading PHP_TokenStream-1.0.0beta1.tgz ...
Starting to download PHP_TokenStream-1.0.0beta1.tgz (7,023 bytes)
...done: 7,023 bytes
install ok: channel://pear.phpunit.de/File_Iterator-1.2.1
install ok: channel://pear.phpunit.de/Text_Template-1.0.0
install ok: channel://pear.phpunit.de/PHP_Timer-1.0.0
install ok: channel://pear.phpunit.de/PHP_TokenStream-1.0.0beta1
install ok: channel://pear.phpunit.de/PHP_CodeCoverage-1.0.0beta1
install ok: channel://pear.phpunit.de/PHPUnit-3.5.0beta1
install ok: channel://pear.phpunit.de/DbUnit-1.0.0beta1
install ok: channel://pear.phpunit.de/PHPUnit_MockObject-1.0.0beta1
install ok: channel://pear.phpunit.de/PHPUnit_Selenium-1.0.0beta1
Happy Birthday PHP! And have fun testing (with) PHPUnit 3.5!
Sebastian Bergmann »
15 April 2010 »
in Articles »
Users of PHPUnit frequently ask me questions such as "How do I use PHPUnit from a Git checkout?" or "How do I run PHPUnit's own test suite?" This article provides the answers to these questions.
Getting PHPUnit from Git
sb@thinkpad ~ % git clone git://github.com/sebastianbergmann/phpunit.git
You now have a phpunit directory in your current working directory that contains the branch for PHPUnit 3.5 (at the time of writing) because the 3.5 branch is currently configured as the default branch for the PHPUnit repository on GitHub. If you want to switch to the branch for PHPUnit 3.4, for instance, you can use
sb@thinkpad phpunit % git checkout -b 3.4 origin/3.4
This tells Git to create a new local branch of name 3.4 (-b 3.4) that is set up to track the remote branch 3.4 from origin (origin/3.4). Git automatically switches to the newly created local branch. Using
sb@thinkpad phpunit % git checkout 3.5
you can switch back to the branch for PHPUnit 3.5.
Running PHPUnit from a Git checkout
Inside the phpunit directory you will find the phpunit.php script. Using this script you can invoke the PHPUnit TextUI test runner:
sb@thinkpad ~ % phpunit/phpunit.php
PHPUnit @package_version@ by Sebastian Bergmann.
.
.
.
The @package_version@ placeholder string for the version information makes it clear that a non-release version of PHPUnit is being used. Upon installation, the PEAR Installer replaces this placeholder string with the relevant information.
Running PHPUnit's Own Test Suite
Running PHPUnit's own test suite is as easy as invoking phpunit in the checkout directory:
sb@thinkpad phpunit % phpunit
PHPUnit @package_version@ by Sebastian Bergmann.
............................................................ 60 / 681
............................................................ 120 / 681
............................................................ 180 / 681
............................................................ 240 / 681
............................................................ 300 / 681
............................................................ 360 / 681
............................................................ 420 / 681
............................................................ 480 / 681
................................SSSSSSSSSSSSSSSSSSSSSSSSSSSS 540 / 681
SSSS.......................................S................ 600 / 681
............................................................ 660 / 681
.....................
Time: 27 seconds, Memory: 56.25Mb
OK, but incomplete or skipped tests!
Tests: 681, Assertions: 1459, Skipped: 33.
Writing code coverage data to XML file, this may take a moment.
Generating code coverage report, this may take a moment.
The above works because there is an XML configuration for PHPUnit (phpunit.xml.dist) in the directory that contains information about which tests to run and what logfiles to produce.
Sebastian Bergmann »
16 February 2010 »
in Articles »
This article is part of a series on testing untestable code:
In a unit test, mock objects can simulate the behavior of complex, real (non-mock) objects and are therefore useful when a real object is difficult or impossible to incorporate into a unit test.
A mock object can be used anywhere in the program where the program expects an object of the mocked class. However, this only works as long as the object can be passed into the context where the original object is used.
Consider the following example:
<?php
require_once 'Bar.php';
class Foo
{
public function doSomething()
{
$bar = new Bar;
$bar->doSomethingElse();
return TRUE;
}
}
?>
<?php
class Bar
{
public function doSomethingElse()
{
print '*';
}
}
?>
With the code above, it is impossible to run a unit test for the Foo::doSomething() method without also creating an object of Bar. As the method creates the object of Bar itself, we cannot inject a mock object in its stead.
In a perfect world, code such as the above could be refactored using Dependency Injection:
<?php
require_once 'Bar.php';
class Foo
{
public function doSomething(Bar $bar = NULL)
{
if ($bar === NULL) {
$bar = new Bar;
}
$bar->doSomethingElse();
return TRUE;
}
}
?>
Unfortunately, this is not always possible (not because of technical reasons, though).
This is where the set_new_overload() function that is provided by the test_helpers extension for the PHP Interpreter comes into play. It can be used to register a callback that is automatically invoked when the new operator is executed:
<?php
require_once 'Foo.php';
class FooTest extends PHPUnit_Framework_TestCase
{
protected function setUp()
{
$this->getMock(
'Bar',
array('doSomethingElse'),
array(),
'BarMock'
);
set_new_overload(array($this, 'newCallback'));
}
protected function tearDown()
{
unset_new_overload();
}
protected function newCallback($className)
{
switch ($className) {
case 'Bar': return 'BarMock';
default: return $className;
}
}
public function testDoSomething()
{
$foo = new Foo;
$this->assertTrue($foo->doSomething());
}
}
?>
Lets run this unit test:
PHPUnit 3.4.10 by Sebastian Bergmann.
.
Time: 0 seconds, Memory: 7.50Mb
OK (1 test, 2 assertions)
Note that there is no * (printed from Bar::doSomethingElse()) in the output above.