Recently we ran into a problem with unit testing a piece of C# code because of the way the objects were created within the class under test. We were using Castle Windsor to inject the dependencies already but this particular situation was troublesome for us.
Consider the following sample code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
AccountFinder depends on the following bit of code to create the right kind of strategy.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
As you can see in the
AccountSearchStrategyBuilder implementation, we end up creating the instances of the strategies themselves because we can decide on the type of the strategy to create only after we inspect the
SearchCriteria. So, that implies testing the
AccountSearchStrategyBuilder would mean creation of the various implementations even though we do not really need them. And the builder needs to be injected with all the dependencies that are required by the individual strategy implementations. Yikes!!
So how do we solve the problem? Castle Windsor has a facility specifically to address this particular problem. The idea is we delegate the creational responsibility to the container whilst still being able to select a particular implementation based on the input available to us at runtime.
The new implementation of the StrategyBuilder looks like
1 2 3 4 5 6 7 8 9 10
This way, we are separating the responsibility clearly - the creational logic of wiring in the right dependencies is not expressed in our code. It stays with Windsor. But how do we use this in our
AccountFinder code? Here is how
First we need an interface that Windsor can implement for the
1 2 3 4
This interface will not have an implementation in our codebase. It is purely used by Castle Windsor to generate a proxy which can be used in our
Our Castle Windsor configuration now looks like below:
1 2 3 4
We are basically registering the
TypedFactoryFacility with the container and then telling Windsor to use that factory to select an implementation type using the
.AsFactory extension method when registering the
The newer version of
AccountFinder looks like below
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
This way, we can test our individual classes easily by supplying mock/stubs instead of dealing with live instances that might require complicated setup.
Use this facility when you need to choose amongst a bunch of implementations based on input received at runtime. Next time you end up Yak shaving, understand why you ended up doing it and see what can be done to ease the pain. And yeah, reading the manual helps too!