Working Effectively with Legacy Code assumes a Test-Driven Development attitude and philosophy, and then tells you how to go into a hairball of existing code and get it to be testable. Chapter titles include "I Can't Get This Class into a Test Harness" and "I Don't Understand the Code Well Enough to Change It," and includes techniques for breaking that bugaboo of unit testing, hard-coded dependencies, like "Extract and Override Method Call," "Introduce Instance Delegator" and "Subclass and Override Method." Excellent stuff.
Mockito is a mocking framework that is just insanely easy to use. Here is a piece of code I wrote where the class to test had a large number of dependencies, and I just mocked out all but the relevant ones. This took me about ten minutes to write, and it was an excellent way to test impact of the changes I was making:
Checkpointable mockCheckpointable = mock(Checkpointable.class); CrawlerContent mockCrawlerContent = mock(CrawlerContent.class); ListcrawlerItems = new ArrayList (); crawlerItems.add(mockCrawlerContent); ContentStream mockContentStream = mock(ContentStream.class); when(mockCheckpointable.getItems()).thenReturn(crawlerItems); when(_mockCrawlerContent.getContentStream()).thenReturn(mockContentStream); _messageManager.sendCheckpoint(mockCheckpointable); verify(_mockContentBuffer).handleContentFromCrawler(mockContentStream, mockCrawler); verify(_mockWalkUpdater).handleCheckpoint(mockCheckpointable);
With tools like this in hand, plus an attitude of commitment to excellence, I now firmly believe you can wrestle your code to the ground and get it into a unit test framework and start improving not only the testability and quality but overall architecture of your code. I don't care if your code is full of massive, crufty code you can't understand, with lots of accesses to the network and the database, you can write unit tests that test modules independently.
So shut up and write those tests. You have no excuses.