It goes without saying that the single most effective way to ensure that the core qualities alluded to previously pervade throughout your project is to test, test and test some more.
Testing can, however, take many forms. Each of the previous qualities has one or more testing methodologies associated with them. Let's look at them in turn.
Good news; you've already done this at least once before, or at least you have if you followed the previous chapter in detail.
We discussed the concepts of unit programming and testing framework earlier in the book, including the theory of why these are good practices to employ in large projects. In the previous chapter, you put that theory into practice in building the application.
Let's recap briefly, however. Unit-driven programming involves constructing your application in neatly packaged, distinct components that have an interface yielding human-predictable results from a given set of a data. A testing framework is then constructed for each component that asserts a series of human-determined theoretical results based on a series of theoretical inputs, and then tests the validity of those assertions by comparing those theoretical results against the actual results derived from the execution of that component's methods.
These frameworks become black boxes that allow you to continuously test the functionality of your components throughout their evolution. You can construct such frameworks, therefore, early in your project, and regression test your components as they evolve and become more sophisticated to ensure that they still produce the results expected. Put crudely, you can test to ensure that your changes have not broken something that used to work!
Unit testing picks up coding errors. Such errors are typically oversights on the part of the programmer. It does not pick up any other form of problem, and hence it is only part of the testing required to ensure high levels of quality with respect to functional compliance. As an example; consider a Web mail application. You may have built a user class, a mailbox class, and a message class. All three may pass your unit tests.
However, consider the Reply button on a message being viewed. It would instantiate a new message object and copy the sender property of the original message object to the recipient object of the message object. This action may not be performed by any specific method in any class and hence may not be the subject of any unit test.
Should the recipient for the e-mail not be set correctly when Reply is clicked, this is very clearly a functional error that needs resolving. It is not, however, one that a unit testing framework would pick up in any three of the tests being performed. You can see, therefore, that unit testing is not the ultimate test of functional compliance; in effect, it tests the model in your model, view, controller (MVC) design pattern.
Functional testing is the other half of ensuring functional compliance quality on your project. It is normally conducted with due deference to the original functional specification of the project.
There are a number of possible approaches to formalizing functional testing. The most important rule to follow is that it is in fact formalized in the first place. Merely having a developer perform a quick run-through of key functionality isn't enough on a large-scale project.
One approach to consider is to assemble a team of test personnel, ideally relatively intelligent individuals typical of your target audience, and issue them formal paperwork for completion. Consider assigning each test team member a specific area of the site to test.
Considering our Web mail example, you may devise a form that looks something like the table that follows. The Action and Expected Result columns should be completed by you in your role as project manager. Your test team will complete the actual result, which you can then use to score each test as either a FAIL or a PASS.
Open the login page by clicking the login link on the navigation.
Login page is displayed, featuring username and password text boxes, and the Submit button.
Enter the login joet1301f and password ixrsh0z1 and press Login.
The form submits and the page reloads, stating that your login is successful. After five seconds, you are automatically transferred to the home page.
Click the Inbox link in the navigation.
You will be taken to your inbox. You will see a number of messages listed. For each message, subject, date received, and sender should be listed. The total number of pages comprising this mailbox will be shown. Previous and Next buttons will be visible if more than one page exists.
Expected result EXCEPT that no Next button displayed despite showing page 1 of 18.
It is, of course, extremely important that any FAIL marks are followed up. As project manager, it is worth assuming a role whereby any failures are first double-checked by yourself and, if found to be genuine, entered into a fault management system, the likes of which we discuss later.
The actions you place on each functional testing paper will of course be derived directly from the functional specification in one form or another. Essentially, you are devising a user journey. Your test team will need to follow the actions sequentially; for example, it will obviously be important that any logins take place before any activity dependent on the user is logged in. Advise your test users that if they find themselves unable to execute subsequent actions due to a block failure, they should mark their paper accordingly and move on.
You must make sure that each branch of the user journey is covered in testing, or at least to the extent at which you can be reasonably confident that the system is functionally correct. A branch occurs every time a decision is made. For example, if logins to your system come in three flavors (say, a normal user, super user, and administrator), you will need to have three initial branches. If for each of these logins a user may choose one of three mailboxes to view, an additional three branches per initial branch will be created.
It may be helpful to draw all the possible user journeys using a tree diagram of some sort, which you can then translate into the previous testing paperwork.
This method of functional testing is not infallible but far more effective than simply asking the development team to "test thoroughly.'' The resulting paperwork also forms a sort of affidavit that can be presented to the client as documented proof that the system has been thoroughly tested prior to handover.
The general principle of load testing is to determine exactly what kind of extreme environmental conditions your application can cope with before it falls over.
The traditional belief is, of course, that it is sufficient to simply ascertain whether the application can support the number of simultaneous users specified in the technical specification, and whether the response times under such a usage level are within a reasonable limit.
A more bullish approach is to keep turning up the amp until the speakers blow. Clients much prefer to be told that "your site can, under its present infrastructure, support 530 simultaneous users'' than simply "yes, it supports the 500 simultaneous users you need it to.'' Knowing that the system has support for only 30 additional users may not be the news that clients want to hear, but it is better that they hear it sooner rather than later.
The principles of load testing are detailed further in Appendix C, "Performance Tuning PHP.''
Cast your mind back to the sample functional testing worksheet discussed earlier in the chapter. We allocated tasks to our testers such as: "Open the login page by clicking the login link on the navigation.''
A similar task in Usability Testing would be simply phrased: "Log in to the system.''
The purpose is quite different, of course, hence the very different phrasing. Usability testing does not concern itself with whether things work; this is taken as read from the functional testing. Rather, it asks how effectively or how easily the user can perform the task in question.
Perhaps uniquely in software testing, usability testing rarely involves questions put directly to the test subjects. Rather, observation is key.
When instructed to, say, "log in to the system,'' the user will be observed, either in person or remotely. Their actions in achieving (or not achieving) the task required of them, which are only in part quantifiable in figures, are of a great deal of interest.
For example, you may want to attempt to answer the following questions:
Where does the user physically look for the login link? Is it where you placed it, or somewhere else? (Note: the position of a user's cursor on-screen is often a clue to where the user is looking.)
What sort of delay is there between when the login screen loads and the user starts typing his or her username?
Does the user visit any other pages in error prior to finding the login page?
The answers to these questions will allow you to formulate a good idea as to the usability of your application. It can, admittedly, be difficult to quantify such research into figures, however.
Usability testing and useful metrics thereof is a huge topic in and of itself and outside the scope of this chapter. More information on the various approaches available can be found on the excellent site www.useit.com, run by Jakob Nielsen himself.