Currently reading "The Art of Unit Testing" by Roy Osherove. I'm about half way through it and so far it's an awesome book. I'm going to ask everyone to leave IOC containers out of this discussion. He only briefly mentions them (actually states IOC are out of the scope of the book which I don't understand and is one of the few places where I can criticize the book). Anyway, with IOC aside the various techniques are:
- Constructor Injection
- Property Injection
- Software Factories and Statics
- Software Factories and Virtual Methods
- Method Injection
- List item
OK, I will describe what I don't like about each method above.
1. Constructor Injection - Makes initializing the object confusing and more difficult, especially if you must pass lots of dependencies.
2. Property Injection - Roy seems to like this technique but it's my least favorite. If you have a bunch of dependencies then the user must remember to initialize each and every dependency that is required for the class. I would say this is error prone and messy. Makes the class very hard to initialize for someone not familiar with it.
3. Software Factories and Statics - While I don't think is to bad of a technique i don't like relying on state. I like dealing with totally stateless object but so far i think its the best technique.
4. Software Factories and Virtual Methods - Similar to the above techniques but allows you to inherit from the class and only override the function that sets your dependency and change it to your stubs. My thoughts are similar to 3 - it just makes it a little too confusing for the person trying to figure out why a unit test failed.
5. Method Injection - All I can say is ewwwwwww... passing in each and every dependency for every method you call. Enough said.
I thought of another way which I prefer over every method listed above. I generally don't encourage conditional compilation but I think in a few places where you use it lightly it can make sense. What I propose is to standardize on a name for a method that sets your dependencies for your testing. For example:
.InitalizeDepForTesting(IFileSystem file, IDatabase data, IEventLog event, ...)
Then wrap the above statement in a conditional compilation statement:
#If DEBUG
public void InitializeDepForTesting(...)
#endIf
So your internal dependencies continue to work as is and don't require a change. You also prevent mucking up the constructor and passing all your dependencies with a bunch of other "stuff". Nothing changes as far as your production code goes and it's very easy to see at a glance how you have to initialize the object for testing. What do you all think?