I'm not a TDD person...or at least I wasn't until last week. Up until then, I had read the blogs and looked at the examples to try to understand TDD and unit testing (with mocking) in general. Almost all of the examples I was shown demonstrated very basic scenarios that, in most cases, were too trivial to show value. I would ask people who would speak about unit testing in general how you'd do a specific scenario and would get mix responses ranging from "just try it" to "you should be using this tool and it'll just write the tests for you".
Last week, I had some free time to where I could truly evaluate a code base I finished up with the prior week and see if I could apply some tests to it. The code I wanted to add tests to were simple repositories where I had abstracted the database calls to separate classes. Being told to mock the databases out in the past, I started to do that and focus solely on these repositories. In some instances, it felt like I was testing the abilities of the mocking framework instead of my code but these methods were simple by design (i.e. "Get Customer by Id 'X'"). It was when I started to test more of the methods that I saw that some of the code I wrote had some issues.
The code was functional; however, it wasn't easily testable. When I would attempt to describe the test, I found that the code did more than one things (breaking the Single Responsibility Principle). Another incident showed that the name of 1 whole class didn't make sense. A third incident showed me an issue with the number of complexities that come from multiple dependencies and object inheritance. After each time that I finished refactoring these issues out of the code and eventually got to working tests, I began to see how the questions that TDD (and BDD) cause you to ask while designing an application really shine.
One example of this was a duplication of code. I had a class called, for the sake of this post, UserRepository. The UserRepository had a method to get all users in the system and returned a List<User> back to the calling code. This class also had a second method that did the same thing but the List<User> only had the FirstName and LastName properties populated. Why did I write such months ago? Short answer - I have no idea. Looking through the code, I found that a different feature needed just the FirstName and LastName properties and nothing else...it was then sending the List<User> to the client for an AJAX call. While I can understand this now, I could have better implemented the solution by if I looked at the scenario and behavior better initially.
If you ever find yourself wondering how writing more code for TDD or just basic unit tests can actually help the code, my recommendation is to just try it. Take a simple class that has only a few pieces of logic in it and test it. Next, take a simple class that has a dependency that you'll need to mock out and test that too. After you understand how to write these basic types of tests, you can move into the self-reflective questions that really shine in TDD. Questions like "What type of data do I want to work with when I call method X?", "What will this class need (a.k.a. dependencies) to get me data Y?", and "Is this functionality already present?" are all questions that get forgotten while we're sometimes blindly coding.
Looking ahead, I can only imagine how my code will be looking.