When you start using TDD seriously, your coding style changes to accomodate testing. Adding tests to an existing code base is hard. Writing tests as you go is easy.

So, the way you do dynamic content on a web page may change to facilitate the abiliity to test. I've not done any PHP work (so I'm not sure how applicable this is to your situation), but I began experimenting with some dynamic content test first approach. Here's what I'm trying out ...

First you separate your static page data from the dynamic part. We don't really care about testing the static part (why? ... ummm ... because it's static). We do care about making sure the dynamic content is correct however.

I choose to use a template system for the static content. The dynamic part choses the template and defines a set of name/value pairs used to populate the template based upon the input to that web page. Then my unit tests just exercise the dynamic portion and make sure that the proper name/value pairs are supplied with the desired template.

Example ...

\n   class LoginPage < Webpage\n     def update(cgi)\n       if valid_password(cgi['account'], cgi['password'])\n          next_page = select_template('start_screen')\n          next_page['account'] = cgi['account']\n       else\n          next_page = select_template('login_screen')\n         next_page['msg'] = 'invalid login, try again'\\\n       end\n       return next_page\n     end\n   end
And the unit test might look like ...

\n   class LoginPageTest\n     def test_good_login\n       page = LoginPage.new\n       cgi = {'account' => 'jim', 'password' => 'goodpassword'}\n       next_page = page.update(cgi)\n       assert_equal "start_screen", next_page.template_name\n       assert_equal "jim", next_page['account']\n     end\n\n     def test_bad_login\n       page = LoginPage.new\n       cgi = {'account' => 'jim', 'password' => 'boguspassword'}\n       next_page = page.update(cgi)\n       assert_equal "login_screen", next_page.template_name\n       assert_match /invalid login/, next_page['msg']\n     end\n   end
That's just a sketch of what I'm trying. I've glossed over some details. Any feedback is welcome.