Wrapping up the StructureMap Automocking Container
UPDATE: I apologize…the original wrapper did not allow injected dependencies. I have fixed this bug and updated the sample.
I have been using StructureMap.AutoMocking with MSpec (Machine.Specifications) and Rhino.Mocks for a few months now. Although I am very comfortable with the patterns that emerge from using the frameworks together, introducing StructureMap.Automocking to other developers is sometimes challenging.
When viewing a specification or test set up with the Rhino.Mocks or Moq automocking container, what is being tested is not readily apparent. Once the concept is explained and demonstrated, these same developers seem to have no issue with maintaining the specifications/tests.
I decided to wrap the details of the container to make the intention clearer and explanation easier. I have started using this wrapper in my projects, and have found it makes building up specifications more efficient in my daily coding.
Let me know whether this is useful to you, or how it could be made more useful.
The Examples
Let’s contrive an example. We’ll say we have a coffee machine that grinds its own beans before brewing. However, the hopper has to have beans before starting the grind. Here is the basic specification:
Action/Behavior
Prepare coffee grounds for 12 cups of coffee
Expectations
Should check that hopper has beans (mock returns true)
Because hopper has beans, should ask grinder to grind enough beans for 12 cups of coffee
We could start without a container, using Rhino.Mocks to build up the CoffeeMachine dependencies manually:
For those of you not familiar with the MSpec style, please refer to the following posts:
**Updated! **From the Morning Brew #487: BDD with MSpec and Rhino Auto Mocks, parts 1, 2, and 3
Here is the same specification using the RhinoAutoMocker class provided by StructureMap.AutoMocking:
Although I think this looks cleaner, the initialization of CoffeeMachine causes some confusion. Unfortunately, a common question would be, “Is RhinoAutoMocker creating a mocked version of CoffeeMachine?" Well, not exactly.
RhinoAutoMocker is an implementation of the AutoMocker base class which uses StructureMap to fill dependencies. The RhinoAutoMocker implementation of the container uses Rhino.Mocks to generate all of dependencies of the target class, whereas the MoqAutoMocker implementation uses Moq. (Optionally, the target class can be partially mocked in order to further isolate behavior.) We then retrieve the class under test (in this case, CoffeeMachine) and its dependencies (IGrinder and IHopper) from the container for use.
If you do not need to setup any expectations in the specification, there is no need to retrieve the dependency from the container. However, in this specification, we need both dependencies.
(Incidentally, I do not like the ClassUnderTest name. I may end up changing this to Instance, ClassInstance, TargetClass, or something similar. Suggestions?)
By moving the initialization of the RhinoAutoMocker to a base class, some of the chattiness of the context can be hidden.
However, we are still initializing and accessing the class in a less than optimal manner.To make the usage of the container a little more seamless, I decided to create a wrapper and factory for the AutoMocker. Setup of the dependencies and expectations are done through an AutoMocker wrapper object. The instance of the class under test is accessed through a ClassUnderTest object.
The Result
The specification (and base class) now look like this:
As you can see, the base class inherits from SpecificationFor. The default constructor uses Rhino.Mocks(MockMode.AAA) to generate the dependencies. It then exposes a AutoMocker object, which is just the wrapper around the AutoMocker base class. It also exposes a ClassUnderTest object. If I didn’t need to use the dependencies, I could make the _Example05_when_preparing_coffee_grounds_ class inherit from _SpecificationFor _instead of inheriting from the base class_._
The Code
I have included the code for the wrapper below for your review. The code and six examples are available on my Google code repository. The repository also includes an example using the MoqAutoMocker. All the examples have the same assertions, but are built up using the different techniques.