Acceptance testing generally involves running a suite of tests on the completed system. Each individual test, known as a case, exercises a particular operating condition of the user's environment or feature of the system, and will result in a pass or fail boolean outcome. There is generally no degree of success or failure. The test environment is usually designed to be identical, or as close as possible, to the anticipated user's environment, including extremes of such. These test cases must each be accompanied by test case input data or a formal description of the operational activities (or both) to be performed - intended to thoroughly exercise the specific case - and a formal description of the expected results.[3]Now, since we're taking a heuristic approach you can skip anything ``formal'' and be realistic. You should have some predefined starting and ending conditions, and some, hopefully automated, way of testing them. But, long before you get to the automated testing part you should have yourself a sit-down with whoever you're developing this thing for and walk them through it, or a mock-up of it. You'll find nine times out of ten that when developing something for a specific group or company it doesn't matter how well it was described it on paper. They'll still say something to the effect of ``Oh, well that's nice, but we need it to [insert thing they never mentioned before].''
Once you've gotten something close to what they actually wanted (as opposed to what they claimed they wanted) you can start putting together some automated tests for it. I really don't recommend spending too much time writing functional tests before this point because it's usually easier with tools like Selenium and MaxQ to just record a correct sequence than it is to tweak an existing one.
Most of the time you'll find that the line between Functional tests and System tests (see below) tends to blur, and that's ok... most of the time, but you should always try and decouple the components of your application as much as possible. If you successfully decouple everything you can use mock objects to represent all the interactions with remote machines or applications and just test the local functionality. For example. Imagine your app sends e-mails. Wouldn't it be better if you could test your system without having to have a working SMTP server, appropriate accounts and permissions, and net access? Just use a mock SMTP server and you can test all your e-mail sending routines without having to worry about potential network failures, processing time for your e-mails as they pass through overloaded spam filters, etc.
K. Rhodes 2007-05-18