views:

47

answers:

4

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:

  1. Constructor Injection
  2. Property Injection
  3. Software Factories and Statics
  4. Software Factories and Virtual Methods
  5. Method Injection
  6. 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?

+2  A: 

a.) I am with the PicoContainer crowd on this: ConstructorInjection is the way to go. Clear semantics and well-defined execution.

b.) About your testing approach: I prefer using Mocks and then rely on IOC for object assembly.

Christopher Oezbek
+3  A: 

Construction injection is the clearer option since it clearly establishes the dependencies you have. If they are too many and confusing, that might indicate a problem with your design.

Otávio Décio
I guess i'm thinking in terms of a brownfield case when your trying to break apart code so it can be tested especially if the constructor your changing is used in a LOT of places. In some cases that's going to be painful. Sure if you design code right from the get go it should be easy to test but thats not the case a lot of times. The amout of change for the solution i came up with would be minimal i think.
I agree that it would be the solution with minimal change, but I question how effective your testing ends up being. Let us know...
Otávio Décio
+2  A: 

Constructor based injection seems to be the clear winner in the community (and is the only method I use anymore).

You ask that IoC be removed from the discussion but that's like asking us to discuss writing .Net code with Notepad. Sure it can be done but why would you want to? An IoC container when used properly usually allows you to at run-time build up your entire application with a single call. From that point on all your instances are properly setup with the right dependencies. And that's not even mentioning all the work being done with auto mocking for unit testing.

And as someone else pointed out if you have so many dependencies that your constructors are confusing you you really need to rethink your design. I'd recommend picking up a copy of "Clean Code" by Uncle Bob after you're done reading Roy's excellent book.

ShaneC
Point taken. Just trying to create an break a depedency on something i'm not all that familiar with yet :P. I understand the concepts but thats about it. Probably going to play around with structuremap after i get done reading the book. Ya "Clean Code" is on my list along witha few others like "Working Effectively with legacy code" (very important where i work).
@user127954 - Both of the books you mentioned are excellent. "Working Effectively..." will cover the issue you brought up in another comment ("a brownfield case when your trying to break apart code so it can be tested") in depth.
TrueWill
A: 

I'm going to ask everyone to leave IOC containers out of this discussion.

By doing this you create problems. I understand your reasoning but, all your objections become moot if you consider a proper IOC.

Ray