The effects of inadequately testing HTML forms are significant, ranging from user frustration due to broken form features to damaging security oversights due to improper input validation. However, the task of HTML form testing is repetitive and mind-numbing. Because of the diverse number of form controls, blend of required and optional fields, and advanced features such as cascading requirements, even relatively simple forms can be submitted using an incredibly large number of permutations, each of which must be tested in order to ensure proper functioning.
Simply enumerating what form characteristics must be tested -- let alone devising a sane approach for manually executing these tests -- can be an overwhelming process. Add the tedium of repetitively conjuring up and entering form data, and the form almost certainly will not be properly tested.
Thankfully, the software community has put a great deal of time and effort into developing automated testing approaches. In fact, most Web frameworks incorporate a native testing solution that can be used to test a wide variety of website attributes and behaviors. One such framework, the Zend Framework, integrates the de facto PHP testing solution PHPUnit (introduced in an earlier PHPBuilder.com article). In this article I'll show you how to get started using PHPUnit and the Zend Framework to test your Zend Framework-driven HTML forms.

Configuring Your Test Environment

Even if you have no prior unit testing experience, it's pretty easy to write and execute automated Zend Framework tests. However, one of the biggest obstacles to getting started is the configuration process. Although an entire tutorial could be devoted to deciphering this process, I'm going to take the shortest path towards getting started by guiding you through this process with little or no accompanying commentary.
When you create a new Zend Framework project using the command-line zf utility, a directory named tests is created within the project's root directory. This directory will house all of the tests you'll write for your website. Additionally, you'll find a file named phpunit.xml, and within the application directory you'll find another file named bootstrap.php. PHPUnit uses the former file to configure certain features and initialize other key information such as the location of your tests. The latter file is used to plug PHPUnit into your Zend Framework-driven website, allowing the tests to execute against the website's actual code. Unfortunately, both of these files are left blank when a new project is generated, so you'll need to add the necessary contents. As I mentioned at the beginning of this section, these details can be a bit complex so rather than get bogged down just download the files (bootstrap.php and phpunit.xml) from my website and replace the empty files with these.
Additionally, download the class ControllerTestCase.php from my site, and place it in tests/application/controller. We'll extend our tests using the class defined in this file, endowing our tests with some additional initialization-related features. I'll come back to this in a moment, so don't worry too much if the contents don't make any sense.
Finally you'll need to install PHPUnit if it's not already available on your system. To install PHPUnit, add its PEAR channel and install it using PEAR's install command:
%>pear channel-discover pear.phpunit.de %>pear install phpunit/PHPUnit

Creating Your First Test

Presuming you're using the command-line zf utility to create your website controllers, then a companion empty test has been generated for you. For instance, if you've generated a controller named About (AboutController.php), then a companion test class named AboutControllerTest.php will reside in tests/application/controllers. Open this file and swap out its contents with the following:
<?php class AboutControllerTest extends ControllerTestCase { public function testDoesAboutIndexPageExist()
{ $this->dispatch('/about'); $this->assertController('about'); $this->assertAction('index'); } }
As you can see, this class is extending the ControllerTestCase class, which also now resides in the tests/application/controllers directory, saving us some additional initialization tasks that would otherwise have to appear in each class.
The test found in AboutControllerTest is a simple one, merely verifying that the About controller's Index action exists and is accessible. You can execute this test and all others residing in the tests/application/controllers directory by navigating to the tests directory and executing the following command:
%>phpunit PHPUnit 3.4.12 by Sebastian Bergmann. . Time: 0 seconds, Memory: 9.00Mb OK (1 test, 2 assertions)
As you can see from the command output, the test passed. Try changing one of the assertions to a non-existent controller or action name and run the test again to see how PHPUnit reports a failed test. Each test is encapsulated in its own method, so just add new methods as you think of new tests. Also, be sure to read the PHPUnit documentation for a complete breakdown of how the testing syntax works.
Also notice the rather long and descriptive method name, which begins with the string test. This naming convention serves two uses in that PHPUnit will consider any method beginning with test to be a test and therefore try and execute it. The lengthy name serves a very useful purpose in that the phpunit.xml file also configures some basic test reporting. You'll find this report in the tests/log directory under the name testdox.html. Open this file and you'll see that PHPUnit has converted that lengthy test name into a human-readable sentence. If the test failed, that sentence will be crossed out, giving you a great visual cue for determining which tests failed and which passed.

Testing a Form

Now that you know how to create and execute a test, let's look at a simple test for a typical login form. Presume the login form, located at /account/login, asks the user to provide an account's associated email address and password. If the information is deemed valid, the user is redirected to /account/profile, otherwise an error message is returned and the form is displayed anew.
We can write a test that verifies this is working as expected. Presuming the account controller is in place and the associated action, view and login form created, open the associated AccountControllerTest.php file and replace its contents with the following:
<?php class AccountControllerTest extends ControllerTestCase { public function 
testValidLoginShouldInitializeSessionAndRedirectToHomePage() { $this->getRequest()-
>setMethod('POST'); $this->getRequest()->setPost( array( 'email' =>
'wj@example.com', 'pswd' => 'secret' ) ); $this->dispatch('/account/login'); $this-
>assertRedirectTo('/account/profile'); } }
Run your tests anew and if the provided email address and password matches a record as retrieved by your authentication mechanism (I use Zend_Auth), then the test should pass!

Conclusion

This brief tutorial only scratches the surface of what's at your disposal when using the Zend Framework and powerful PHPUnit test framework together. However, it should be enough to help you introduce some semblance of sanity into your approach to Web development, not to mention save you bunches of time otherwise spent testing tedious features. As always, if you have any thoughts or questions, please add them in the comments, or ping me on Twitter at @wjgilmore!

About the Author

Jason Gilmore is the founder of WJGilmore.com and the author of several popular books, including "Easy PHP Websites with the Zend Framework", "Easy PayPal with PHP", and "Beginning PHP and MySQL, Third Edition".