Retrofitting XP-style Testing onto a Large Project?
Mr Pleonastic submits this query for your consideration: "I work for a small startup (ok, me and another guy comprise the entire development team) that has somehow managed to survive the bust, attract a number of customers, and build up about 300K lines of functionality. Up to now we've made it by being smart and conscientious hackers, but I'm increasingly embarrassed by our shortcomings in testing. I like the XP approach to making enduring, automated test suites, but most of what I read about XP focuses on obvious stuff and changing your programmer culture at the outset. Does anyone have experience with, or advice for, retrofitting it onto a fairly mature project? What do your test suites look like, anyway? The bugs I fear most are of the 'If the user does X and then Y, the result blows away our assumptions' variety, not the 'Oops! My function returned the wrong value' variety (which happens of course). How do you write good test code for the former, without spending even longer debugging the test code? Is XP just for small, new projects?"
I once did a little palm programming, and I remember the emulator had a mode where it would randomly click on various controls and enter text really quickly, as a way of stress-testing your app, testing it's ability to handle any combination of input and options without blowing up. I wonder if something like that would be useful if the world of typically much-more complex PC programs...
A Minesweeper clone that doesn't suck
Not what it doesn't.
As a start write down test specs for all of your use cases, even if the specs aren't automatizable. Then find a tool to simulate the user (e.g. HttpUnit is very good to simulate web users) and try to turn the specs into functional tests. Ensure that your application works today.
The next step is remodularizing your code, try to find a tool that traces dependency diagrams in your code (e.g. Compuware's Pasta is an excelent free tool for Java). Module interdependency is a strong smell of bugs, so refactor them to make the dependencies acyclic, running your tests to keep everything under control.
Then try to write unit-tests for the modules, create mock objects from them and check if they do what they're supposed to do. Repeat the second step for your classes (or data structures and functions if it isn't OO). Try to make all dependencies acyclic and create unittests for them.
And during all these steps use Design by Contract to write down *all your assumptions*. Leave them on production code too (unless it's strictly necessary for performance). That way if your code breaks your assumptions the contracts will tell you. Also it'll force you to rewrite some code to make it checkable (i.e. exposing invariant predicates).
Finally don't forget to check the common XP areas (extreme programming in Yahoo! Groups and news://comp.software.extreme-programming).
It'll be no piece of cake but when you start to see a better factored code that keeps the bar green you'll be rewarded.
Disclaimer: If I disagree with you I'm probably trolling...
1) *Everytime* you discover a bug from now on, write a test case that exposes it. Then fix it.
:-)
2) Write new functionality test first. You are not allowed to implement new features unless you first implement a test that fails. Once in runs you are either done, or you got ahead of yourself and need to get back to writing a few more tests
I ran across an article a couple of years ago by Chuck Allison in C/C++ Users Journal about the The Simplest Automated Unit Test Framework That Could Possibly Work. It included test frameworks written in C, C++,and Java and opened my eyes to doing best practices to the extreme. It also showed me how I could apply unit testing to my C code. You can download free Test Frameworks (Test Suites) for other languages.
Unit testing was the first XP key practice that I started to use. When I would have to make a change in my mature code, I would add a unit test section to the module I was changing (using #define TEST), and add a main() to execute the unit test (using #define TEST_MODULENAME). See examples of this on my software page. I then began using test-first programming by writing the unit test first, seeing it fail, then writing just enough code to make it pass.
Other extreme programming sites that have been useful have been extremeprogramming.org , which has a great tutorial that includes an introduction and overview, and the site Extreme Programming.