Other Articles in the SeriesPart One: Introducing xdebugPart Two: Tracing PHP Applications with xdebug Part Three: Profiling PHP Applications With xdebug Part Four: Debugging PHP applications with xdebug Part Five: Creating Code Coverage Statistics with xdebug Welcome back to the fifth and last installment of our series of xdebug articles on Zend DevZone. xdebug is the swiss army knife extension for PHP developers. In addition to some nice features like beautifying Today, we will have a look at another great feature of xdebug - creating code coverage statistics. Code coverage statistics show how many times each line of the code has been executed. Conversely, they also show which lines of code have not been executed, which is in fact much more interesting. As we know, each program has different execution paths (unless a program has no branches at all). A program‘s execution path depends on the input data, which includes the parameters passed to the program, but any data in the database or from other data sources. As an example imagine a website that allows you to create a user account. This account must be verified by visiting a link that is emailed to you. If you log in to a website, you might see a different response depending on wether you have already confirmed your account or not, though the GET or POST data passed to the script is the same. In this case, the program‘s execution path depends on the confirmed flag of the user record in the database. Code coverage statistics of one single program run are not very useful. But when we collect and aggregate code coverage statistics of many program runs (with different execution paths), the coverage statistics show us which program parts have not been executed. These parts are either obsolete or should be tested. The preferred way of creating code coverage statistics is to run unit tests while collecting coverage statistics of the tested code. Note that coverage statistics are not created for the unit tests themselves, but of the code that we are testing. A unit test is a test of a class, module, or any other part of an application. Unit tests make it much easier to feed different input data to the code to test than if we would be testing an application in whole. Technically, creating code coverage statistics is a rather complex issue that involves various tools. Coverage statistics in xdebug are basically an array for each file where the line number is the array key and the array value is the count how often this line has been executed. We‘ll need some other tools to visualize these coverage statistics. To run automated tests, and collect the coverage statistics that xdebug provides, we will use PHPUnit. To make testing with PHPUnit easier, we will use the build automation tool phing, which allows us to define a file set of all tests, run PHPUnit tests on each of these files, and gather and aggregate the collected coverage statistics. phing also converts the coverage statistics to a nicely formatted HTML report using XSL. Assuming that you (still) have xdebug installed on your system, we‘ll need to install the other tools before we can start. Installing phing and PHPUnitphing is based on the build tool Apache Ant, which is written in Java. phing was created so that no Java Runtime Environment would be required to automate build processes on PHP development systems. The main advantage of phing over Ant is that you can extend phing by writing your own PHP classes. To extend Ant, you need to write Java code. To install phing, you need PHP 5 with XML and XSLT support. On Unix, you must compile PHP with the configuration switch To activate XSL support in PHP on Windows, you must load an extension by adding
to php.ini. Remember to restart your web server to make the change effective. On Unix, the XSL extension is named phing is deployed as as PEAR package. To install phing, you must have a PEAR environment on your system. Run pear upgrade-all PEAR pear channel-update PEAR Normally, when we install phing with the switch pear channel-discover pear.phpunit.de pear install pear.phpunit.de/phpunit Now we can install phing. As I write this article, the current version of phing is 2.3beta1. The PEAR installer will automatically install the latest version of phing, but since this version is in beta state, you should add the command line swich pear channel-discover pear.phing.info pear install --force --alldeps pear.phing.info/phing phing is based on XML files that define the various targets ("jobs") of a build process, like build, test, or - for web sites - deploy which might copy the web site right to the live server. The XML format makes phing builds portable across different platforms, unless, of course, you rely on Creating unit tests with PHPUnitNow that we have installed all necessary tools, we must create some unit tests. I would recommend keeping the tests in the same directory tree where your production code is kept. When deploying your application, you can always leave out the test files, unless you want to create version that allows your end users to run the unit tests as well.
<?php require_once ‘PHPUnit/Framework.php‘; require_once ‘a(chǎn)utoload.php‘; class FooTest extends PHPUnit_Framework_TestCase { public function testFoo() { $foo = new Foo; $this->assertEquals(0, $foo->getNumberOfBars(), ‘Foo is not empty‘); $bar = new Bar; $foo->addBar($bar); $this->assertEquals(1, $foo->getNumberOfBars(), ‘Foo has no bar‘); } } ?> This example shows a rather simple unit test that makes not much sense by itself in the real world, but serves to illustrate the purpose. A real-world test case would probably contain more test methods and does not even use a test fixture. We assume that autoloading is used, so that the Creating a phing build fileFor the purpose of this article, our build file will have only one task that creates code coverage statistics. By default, phing build files should be named
<?xml version="1.0"?> <project name="my_project" default="code_coverage" basedir="."> <fileset dir="src" id="php"> <include name="*.php"/> <include name="**/*.php/"/> <exclude name="*Test.php"/> <exclude name="**/*Test.php"/> </fileset> <fileset dir="src" id="tests"> <include name="*Test.php"/> <include name="**/*Test.php"/> </fileset> <target name="code_coverage"> <mkdir dir="coverage_db"/> <mkdir dir="coverage_result"/> <coverage-setup database="coverage_db/coverage.db"> <fileset refid="php"/> </coverage-setup> <phpunit2 codecoverage="true"> <batchtest> <fileset refid="tests"/> </batchtest> </phpunit2> <coverage-report outfile="coverage_db/coverage.xml"> <report todir="coverage_result"/> </coverage-report> </target> </project> Like in PHP itself, always use forward slashes as directory separator, even on Windows. We are using two filesets, Each fileset has a base directory, src that is specified in an attribute of the In the The Now the In many cases, you want phing to stop the build when unit tests fail. You‘ll probably not want to create a release when you know that the code did not pass all tests. To stop a build when a test fails, you can use the It is important to distinguish between an error and a failure. A failure is a failing assertion in a test. For example, if you expect a function to return When creating code coverage statistics, however, we want to execute all unit tests, regardless of how many of them fail or have errors. It would not make much sense to stop calculating the coverage statistics when the first test fails. When you create a beta release of your application, you might accept failing unit tests, but probably no errors, as you wouldn‘t want your application to crash due to a PHP error at runtime. Gathering coverage statistics with xdebugThere are no php.ini settings that control the creation of code coverage statistics. Gathering of the statistics is turned on and off by PHP function at runtime, allowing for a fine-grained level of control over which pieces of code to create coverage statistics for. To start gathering code coverage statistics, use When using PHPUnit together with phing to run the unit tests and gather code coverage statistics, you will never have to worry about using these functions. PHPUnit will use them for you to collect coverage information about the tested code. Putting it all togetherWhen working with PHPUnit, you need to define a test suite as a collection of tests to run multiple tests with one command. Using phing frees you from having to deal with test suites, since all test cases in the given file set are executed. You just create as many individual test case classes as you like, define a fileset that includes all test cases, and have phing run all tests. It couldn‘t be easier. Like PEAR and PHPUnit, phing has a command line interface. To execute a build target, run
This makes phing execute the target, which includes running all unit tests, collecting the coverage statistics, and then creating the HTML report of the code coverage statistics, even if one or more unit tests fail. The following screen shot shows the HTML report generated by phing. This report is located in the coverage_result subdirectory of your build directory, with your build directory being the directory where build.xml is located.
Code coverage statistics can help you find parts of an application that are never executed, respectively tested. Do not over-estimate the value of code coverage statistics. Even 100% code coverage does not mean that your code is thoroughly tested, as the following example shows: <?php ... if ($a) { print ‘1‘; } else { print ‘2‘; } if ($b) { print ‘1‘; } else { print ‘2‘; } ... ?> This small code snippet (which, admittedly, does not make much sense in the real world) outputs numbers based on the values of
You could achieve 100% code coverage just by testing the combinations ( Code coverage statistics are a nice way of getting a feel for the test coverage of an application. But please do not overestimate the code coverage. Even 100% code coverage does not mean that your code is bug-free or even thouroughly tested. Still, a high code coverage certainly helps building trust in the code quality of your application. More important than achieving a high percentage of code coverage is the fact that the statistics show you potentially critical, and untested parts of the code. These are the parts you should focus on, either by creating tests for them, or by removing them because they are obsolete. ConclusionThese five articles should have given you some good reasons to start using xdebug, which really is a very good tool. I could not do without xdebug on my development system, even if it was only for the This article ends our series of xdebug articles, so I would like to thank you for joining in. I hope you have enjoyed reading the articles as much as I enjoyed writing them. Very special thanks to Derick Rethans for creating and maintaining xdebug. And to you: Happy coding - and since you have become an xdebug user now, please remember to send a postcard to Derick. |
|