Now that you know what unit testing is and how to write and run tests, it’s time to look at writing tests in more depth.
Today we’ll take an example class and write tests for it. We’ll also introduce some common testing methodologies.
Unit Testing as a practice is like any other - there are good practices, and bad practices. Two of the worst practices are overloading tests with assertions, and writing lazy or shallow tests.
Before we recount the dire consequences of these practices, it's worth knowing why they are so attractive and not immediately perceived as being bad. In short, every test you write requires that you setup the test environment, create a scenario for possible failure, add an assertion, and then ensure the source code makes that assertion pass. This requires code - sometimes a lot of code. So adding multiple assertions to each test minimises the work needed to write tests, since using multiple assertions takes advantage of existing code to avoid writing new stuff to clutter your test classes. It can also help to tackle multiple but related results in the same test.
We recently looked at front-end testing of web applications with Selenium. Today, we’ll take another approach to testing your PHP applications: backend unit testing for your actual PHP code. As part of our posts on test driven development, here’s a quick intro to using SimpleTest to test your PHP applications.
SimpleTest is a PHP unit testing and web testing framework along the lines of JUnit and JWebUnit. It provides a comprehensive set of APIs for testing everything from your class methods to your SSL-secured authentication pages.
Unit testing in PHP generally validates that individual sections of your source code are functioning as expected. As your project grows, it’s hard to remember what each and every module is responsible for, especially with multiple developers. Unit tests help check that a function or method does what it’s meant to, and when run during a build process or around version control commits, can check that recent changes haven’t broken expected functionality.
To provide a flexible and extendable software, it is a good OO practice to reduce the dependencies between implementing classes. This could be achieved by developing against abstractions which means both, abstract classes and interfaces. By using abstractions instead of real implementation in the application you provide some sort of contract, that could be used by others to hook into the application with their own classes that fulfill the contract. Except the extensibility of an application a good abstraction reduces the risk of breaks in multiple subsystems when something was changed in a single package. But how to get rid of all these dependencies, doing this by hand will become an impossible job, at least for larger projects. At this point a tool should be used to assist the development process.
PHP_Depend is an adaption of the established Java development tool JDepend. This tool shows you the quality of your design in the terms of extensibility, reusability and maintainability. All these facts are influenced by the inter-package dependencies and the package abstraction that PHP_Depend visualizes in form of an abstract/instability chart and as a detailed XML report of all detected dependencies.
Testing is an essential aspect of developing in any programming language. If you don't test your source code then how can you verify it works as expected? Manual testing can only be performed irregularly and usually only in limited ways. The answer to testing source code regularly, and in depth, is to write automated tests which can be frequently executed. In PHP such tests are usually written using a unit testing framework, a framework which allows the source code of any application or library to be tested as isolated units of functionality such as a single class or method. As unit testing has gained popularity, it has become a standard practice in PHP with libraries and frameworks such as Swiftmailer, the Zend Framework and Symfony all requiring unit test coverage of their source code.
Unit Testing is often seen as an arcane, time consuming task - which it sometimes can be! But the point of spending time writing tests is to improve the quality of your source code so it has fewer overall bugs, many of which are detected early, a continual testing process to prevent new changes from changing the behaviour of older code, and to provide confidence that your code can be depended on. There are other benefits too, and we'll detail these later.
I was recently working on a command line PHP tool, and didn’t have easy access to our normal PHP unit testing framework built around SimpleTest. After a few lines of non-test-driven-development, I started to freak out a bit - I guess I’ve fallen for the view that if code doesn’t have tests, it’s broken.
I didn’t need support for mock objects or complicated assertions - just a bare basic assertTrue() would do the trick. So, I present “pTest”, in 9 lines of code.
One of the problems that hampers the testability of PHP code is the coupling created by accessing all of the PHP global functions. This happens often because a large number of useful extensions are accessed only through global functions.
I created my own test runner to run tests inside Vim, I can't remember how long ago. Must be a year or two. I never shared it with the world. It was too primitive for anyone else to use. Then, recently, I decided to try re-implementing it in a more serious way. That meant using a more sophisticated programming language. Vim script has seen some improvements and is pretty useful for simple tasks, but I want something that's object-oriented and has a test framework. That means Perl, Python or Ruby, all of which are available from inside Vim. So I've started doing it in Ruby.
In this article I introduce the topic of Acceptance Testing (aka Functional Testing), something more PHP programmers should be starting to practice. I'm sure many of us are well aware of Unit Testing and even Integration Testing so where does this third wheel come into play for web applications given our growing obsession with Web 2.0 and AJAX and how does it differ from the former two practices? Below I'll explain this. I will also introduce how to implement Acceptance Testing using the killer combination of PHPUnit and Selenium.
I just started listing the techniques I've learned when writing tests to exercise the web interface of a PHP application. This is from my experience and my personal preferences; it's not the final word or necessarily right for everyone.
The idea of being able to record and play back tests, as you can do with Selenium, is tempting. But I want to be able to program the tests. Programming in this context means anything from simple conditionals and loops to advanced test patterns (see http://xunitpatterns.com). That way I can achieve a much more sophisticated test organization, and more flexible and robust tests.








