Roy is talking about legacy code, and has some great tips about it. I would like to re-iterate the recommendation for TypeMock for legacy code. I still think that it is preferred to limit TypeMock to legacy code, but that is another issue.
There is another approach that I would like to mention, which is fairly radical and takes a while.
Break The Code.
You can do a lot with R# just blindingly doing Extract Method (Ctrl+Alt+M). At one point I had a classs with:
Those were an intermediatery state, just to allow me to try and figure out what the hell CommandHandler.Run() should do. For large code bases, Extract & Delegate is also an option, you push the functionality to another class, but keep the same interface and behavior.
I had several cases where I not only had code bases with red tests, but the code could not compile for long period of times (two hours!) as I worked to push everything into place. I tend to scare some people because I am very trigger happy on the delete key (CTRL+Z & Subversion), to the point where I here this tiny "Eek!" if they see that I am selecting code :-)
Just to be clear, this is rarely a valid approach unless you are familiar with the code base and/or sure that you have any reasonable chance of at least manual QA. The worst position is where you can't understand neither the code nor its results. (Part of the reason that I hate doing trouble shooting on other people's code, I can't just delete stuff that I don't understand).
Even so, just following the structure of the code can give you some ideas about how to do some extraction, which can be of great help in understanding the code. Unfortantely, all of the above are time consuming tasks, maybe a better approach would be Cover & Ignore.