I'd really like to start implementing Unit Testing in my projects. I don't know how viable this is to do in PHP. If anyone has done this, how was it implemented? Did it increase productivity?
There is a PHPUnit testing framework that is developed in native PHP and used by projects such as the Zend Framework. I haven't used it since it split from the PEAR project but it was pretty good back then so I imagine it has only gotten better. As for productivity increase, that is all in how you or your team cope with unit testing and your millage may vary.
phing can be used to automatically run PHPUnit, and used with something like xinc you can completely automate it if you are using SVN.
I think you should check out Simpletest - we found it much easier to use and get started with than phpUnit.
No, it won't increase productivity; it will improve your code though, and overall should make everything better.
We've started using unit testing at work, but it works best when tests are written at the same time as your code. It's slow work retrofitting it to existing code, but we are trying to write tests for all new stuff.
There is a book called Enterprise PHP by Ivo Jansch which has just been published and covers unit testing as well as other best practices; I saw Ivo's keynote speech on the same topic at PHP London this year and it should be an excellent book for anyone who wishes to work more effectively with PHP.
With PHPUnit you can call the standalone binary phpunit < classname > to run all the unit tests in < classname >.php. You can group up tests in a test suite and run them similarly with phpunit.
Unit testing PHP will make your code stronger. Code that is testable tends to be better organized (more modular, with cleaner APIs) than code that is hard to test. We have been using both PHPUnit and SimpleTest at RadicalFusion for several years.
I personally prefer SimpleTest. There is a command line test runner and web-based test runner, and there is even an Eclipse plugin to let you run unit tests from the IDE itself. I found the Zend to PHPUnit connection much harder to get working, especially with the debugger.
The way we use SimpleTest in-house is with a continuous integration script that we wrote ourselves. Every time we check in a feature to SVN we include the unit tests. Every hour or so, the CI script runs and calls a command line PHP script that runs all of our unit tests. If any break, I get an email. It's been a great way to reduce bugs in our systems.
You could always use a post-commit hook of CVS or Subversion to automatically run your tests. Or use a continuous integration tool such as phpUnderControl http://www.phpundercontrol.org Xinc http://code.google.com/p/xinc/
Both SimpleTest and PHPUnit are essentially 'XUnit' based testing tools, and have a very similar API. The main differences are style and internal architecture. PHPUnit is structured much more formally, and uses PEAR naming conventions, wheras SimpleTest has a tighter, more pure classic OO style internally. At a high level, writing test cases, the differences are minor, but they do come into play when you want to extend the tools.
SimpleTest has an easier extension API, and is more flexible in terms of reconfiguring the reporter output to do things like send emails on failure (good for continuous integration) or output different XML formats.
Another SimpleTest feature which you might find useful is the WebTester, which provides a basic HTTP client wrapped in a browser-like API, so your tests can navigate web pages, fill out forms, and check HTTP response codes.
I have used PHPUnit and found that it provided the usual benefits of unit testing, namely:
- forcing you to think carefully about your code's design, including edge cases / error conditions
- catching errors early so that you minimise time spent
- repeatable tests give you the ability to regression test easily, and therefore give you more confidence to maintain higher quality code through refactoring
For your unit tests to be useful, they ideally need to exercise a high portion of your code (that is, have good code coverage).
Re. productivity, there is an initial overhead for creating the tests but if your codebase is going to be maintained over a significant period of time you will get the payback through repeatable automated tests which catch errors early.
I've tried SimpleTest and PHPUnit, and stuck with PHPUnit because it works with PHP 5, and SimpleUnit seemed to throw a lot of notices and warnings (I like to develop with full error reporting turned on, there's no excuse for sloppy code). I also came across numerous bugs with SimpleTest (some of which caused me hours of wasted productivity and stress in trying to track them down).
In terms of how unit-testing helps development, I find TDD (Test Driven Development) to be the best paradigm, because it forces you to think exactly how your code will be used before you write any of it. In fact, since I've adopted unit-testing and tdd, I've rewritten much of my own code because in writing tests for them, I've realised that my method names and functions weren't exactly the most intuitive, and also did some things that they shouldn't have been doing (i.e. like doing two tasks, instead of being specific and just do one each).
Not only that, but writing tests for your code helps you understand your own code better (i.e. in that it helps you realise when your all-singing-and-dancing class is doing too many different things, and should be split up into different distinct components), and also helps others understand your code (because if you write your tests properly and elegantly, they can see how they're supposed to use your class - it's almost like writing code examples).
There's a good guide involving a bowling game here that gives you an insight to both PHPUnit and TDD, and that should help you get started. It starts from slide 14.
I'm surprised nobody mentionned phpUnderControl - it's a patch to CruiseControl which is to the Java community what Phing is for PHP.
I've tried both, and really, CruiseControl + phpUnderControl is much more reliable as far as I could go.
What you need is:
- CruiseControl + phpUnderControl (listens to SVN, and run a build when a commit occurs)
- PHPUnit (unit tests)
- Selenium RC with PHPUnit (records macros within a browser and replay them to do functionnal specs)
phpUnderControl also sets up phpCodeSniffer (that you should tweak to match your coding style), and code coverage analysis. It's all very simple to set up, and very tightly integrated... (phpUnderControl is hosted with phpUnit - that tells you all).
Whatever you choose, take the time to setup your continuous integration environment, it is rewarding.