Design principles and testing – part 4
Let’s take a moment and think about what this programming to an interface and not an implementation can do for us. For instance, imagine that you want to test the following scenarios.
1. The service is unavailable and thus throws a System.Net.WebException (I’m guessing here, I have no idea what exception is actually thrown). You want to make sure that your application handles this in a graceful manner.
2. Your design buddy wants to make sure that all the icons he created for the difference weather types (cloudy, sunny etc) looks ok so she asks you to make sure that you find dates that satisfy those types.
Setting up state
This is a pretty common predicament, that you need your application to be in a certain state for you or your colleagues to verify something. Sure, this can be accomplished by changing the code to do whatever it needs to do at the moment but it’s not a very solid approach.
Since our service now only cares about the concept of a weather repository we can write implementations that are tailored to satisfy a specific state.
For scenario one we want the code to throw an WebException. And no, launching the site and then quickly pulling the network cable to trigger the timeout is not a professional approach =)
1: public class WeatherRepositoryThrowsWebException : IWeatherRepository
2: {
3: public XElement Load()
4: {
5: throw new System.Net.WebException();
6: }
7: }
Scenario two would probably be quite a few classes but they would all look something like this
1: public class WeatherRepositorySunny : IWeatherRepository
2: {
3: public XElement Load()
4: {
5: return new XElement("root",
6: new XElement("time",
7: new XElement("temperature", new XAttribute("value", 20)),
8: new XElement("symbol", new XAttribute("number", 2))
9: )
10: );
11: }
12: }
So setting up state turns into choosing which class to use and not about changing existing code. This is now handled in our factory but there are much better tools to use for this, namely IoC-containers.
Using StrucureMap
For those of you who attended Fredrik Karlssons talk at EPiPS2010 you already know that EPi (probably) are including StructureMap as their IoC-container of choice in vNext. All the available containers can basically do the same thing (although they have another syntax) so nothing shown here is specific to StructureMap.
The purpose of the container is to configure all our dependencies in one place so that we can keep that information away from our code. Let’s take a look at how this can typically be configured.
The basic setup we do is that we tell StructureMap which concrete class we want to use for a certain interface (again, the concept of interface, not the type) which in it’s simplest form looks like this
1: For<IWeatherRepository>().Use<YrNoWeatherRepository>();
Pretty self explanatory wouldn’t you say? A common way to handle the setup for structuremap is creating a bootstrapper that’s executed as part of the application start event in global.asax (or in EPi’s case a event that’s fired after it has done all the necessary configuration).
1: public static class StructureMapBootstrapper
2: {
3: public static void Bootstrap()
4: {
5: ObjectFactory.Configure(
6: x => x.AddRegistry(new WeatherRegistry())
7: );
8: }
9: }
1: public class WeatherRegistry : Registry
2: {
3: public WeatherRegistry()
4: {
5: For<IWeatherRepository>().Use<YrNoWeatherRepository>();
6: }
7: }
So, now what we have that setup we simply asks the StructureMap container for the service and let it resolve all the dependencies.
1: ObjectFactory.GetInstance<WeatherService>()
What StructureMap does here is that it looks at the greediest (that is, has most parameters) constructor for WeatherService. In our case it’s the constructor that takes a IWeatherRepository. So it looks through it’s configuration and fetches whatever we told it to use when it stumbles upon that interface. In our case it’s the concrete class YrNoWeatherRepository.
Auto-wiring
In the example above our Service only had one dependency but it’s pretty common for our classes to have more dependencies than that. Imagine that the service in addition to the repository also had a IWeatherMapper and that the repository in it’s turn had a dependency to some IDataConfiguration. This is were the usage of a IoC-container and it’s auto-wiring really shines.
Let’s say that we change the constructor of the YrNoWeatherRepository to
1: public YrNoWeatherRepository(IDataConfiguration config)
2: {
3: // code code code
4: }
Develop features and not infrastructure
Another nice usage of an IoC-container would be our function that formats input from the user according to certain rules. We left the classes like this from our last refactoring
1: public void FormatAndSave(PageData pageData, string toFormatAndSave)
2: {
3: var formatters = new List<IMainBodyFormater>()
4: {
5: new MainBodyFormaterNewLine(),
6: new MainBodyFormaterAt(),
7: new MainBodyFormaterAuthenticated(),
8: new MainBodyFormaterNotAuthenticated()
9: };
10:
11: var formatedText = new MainBodyFormater().Format(toFormatAndSave, formatters);
12: new EPiServerRepository().Save(pageData, formatedText);
13: }
So we’re building a list of formatters (classes that implements IMainBodyFormater) and send it to the MainBodyFormatter. Let’s rewrite this to use constructor injecting into the MainBodyFormatter.
1: public MainBodyFormater(List<IMainBodyFormater> formatters)
2: {
3: this.formatters = formatters;
4: }
Now we configure our formatters and StructureMap is smart enough to realize that since we have a dependency to an array of IMainBodyFormater it takes all classes that implements that interface that we’ve added and passes them in.
1: For<IMainBodyFormater>().Use<MainBodyFormaterNewLine>();
2: For<IMainBodyFormater>().Use<MainBodyFormaterAt>();
3: For<IMainBodyFormater>().Use<MainBodyFormaterAuthenticated>();
4: For<IMainBodyFormater>().Use<MainBodyFormaterNotAuthenticated>();
1: public void FormatAndSave(PageData pageData, string toFormatAndSave)
2: {
3: var formatedText = ObjectFactory.GetInstance<MainBodyFormater>().Format(toFormatAndSave);
4: new EPiServerRepository().Save(pageData, formatedText);
5: }
We can even take this a step further and simply ask StructureMap to scan our assembly and add all classes that implements the interface
1: Scan(x =>
2: {
3: x.TheCallingAssembly();
4: x.AddAllTypesOf<IMainBodyFormater>();
5: });
So now adding a new formatter becomes as simple as implementing an interface and placing it in an assembly that’s scanned (you can configure that to be a specific assembly, all assemblies or pretty much anything you want) and it will automatically get’s passed into the MainBodyFormatter. So you don’t have to change or worry at all about the infrastructure of your code to add features.
About ObjectFactory.GetInstance…
You’ll want to try and limit your calls to ObjectFactory.GetInstance throughout your code and instead leverage the power of auto wiring. For instance, it’s quite possible to do this
1: public WeatherService()
2: : this(ObjectFactory.GetInstance<IWeatherRepository>())
3: {
4:
5: }
6:
7: public WeatherService(IWeatherRepository weatherRepository)
8: {
9: this.weatherRepository = weatherRepository;
10: }
The problem with this is that now your weather service is tightly coupled to StructureMap. So you’ve basically just traded one hard dependency for another.
If you’re using MVC what you want to do is to use the ControllerFactory and control the creation of the controllers and handle all your dependency resolving there. When it comes to WebForms it get’s a bit trickier since you can’t control how your Page objects are initiated. There are workarounds using setter injections, I’ve blogged about that here.
Naturally there are many more things an IoC-container can do for you than what I’ve shown here so I really encourage you to head over to their website and read more.
Nice post again Stefan.
Thanks!
/ Stefan Forsberg
Thank for very much for this excellent series of posts.
/ Emil Lundin