Design for Testability – Structure map (Part 6)

On my quest to design for testability, I’ve already covered:

(In case you don’t know what Inversion of Control (IoC) containers are, I advise you to take a peek at Part 4 of this series first before continuing  with this article.)

Today’s post will cover what IoC looks like when using StructureMap, which was developed (and is maintained) by Jeremy D. Miller, The Shade Tree Developer. In this post, I’m using the current production version (2.0). Once version 2.5 is published, I’ll cover it in separate post.

In contrast to Castle Windsor, the StructureMap framework only contains a lightweight IoC container without any additional unrelated parts. You can download the zip file containing StructureMap here. After you unpack the zip file, simply add a reference to "StructureMap.dll" to start using it.

Summary of the changes required by StructureMap

Once again, I will use the same code from Part 3 (manual DI based on internals) and transform it with StructureMap to something very similar to the Windsor example in my previous post. All the internals will be removed and DI injection will be replaced with service locator. Components will pull in their dependencies from a "well-known-object" implementing the Service Locator design pattern.

Something like this:

 image_thumb2

(All of the types are contained in the assembly "UserManager.dll" and their name space is Example.UserManager. The solution also contains a Console application which calls the UserManager method to illustrate how to use the Service Locator in production.)

As you can see, we now have three fully separate types without most of the DI plumbing code and which we locate (when needed) by using the built-in functionality of the Castle Windsor DI framework.

A major difference between the code in this example and the code in the Windsor example is that the StructureMap framework provides a built-in service locator facade type, so you don’t need to write the ServiceLocator type yourself.

Another major difference between StructureMap and Castle Windsor is that StructureMap supports attribute-based definition of container components without any configuration files, which can be a major advantage for people who don’t want to dig into the bowels of XML configuration files.

StructureMap container configuration

Most of IoC containers are based on same concepts:

  1. using an interface to define an abstraction,
  2. having concrete classes implement that abstraction,
  3. and providing the IoC container with a mapping between the abstractions and their implementations.

In the StructureMap framework, abstractions are called "PluginFamilies" or "PluginTypes" and concrete implementations are called "Plugins" or "PlugedTypes".

There are three different ways of providing StructureMap with the mapping information it needs to perform as an IoC container:

  • Configuration based implementation
  • Attribute based implementation
  • Manual IoC definition

Configuration based implementation of StructureMap

In a configuration based approach, StructureMap works almost the same as Castle Windsor. During the application initialization, StructureMap reads the configuration file (by default the name of configuration file is StructureMap.config) and gets the list of mappings between the interfaces (PluginFamilies) and types that implement the interfaces (Plugins).

The configuration file can be written in a few ways. In my example, I only have a single Plugin (instead of multiple types implementing the same interface). For this type of mapping, the easiest way to write the configuration file is to use the DefaultInstance element.

The configuration file looks like this:

<?xml version="1.0" encoding="utf-8" ?>
<StructureMap>
  <DefaultInstance
    PluginType= "Example.UserManager.IUserManager, UserManager"
    PluggedType="Example.UserManager.UserManager,  UserManager"
    Scope="Singleton"
  />
  <DefaultInstance
    PluginType ="Example.UserManager.IUserProvider, UserManager"
    PluggedType="Example.UserManager.UserProvider,  UserManager"
    Scope="Singleton"
  />
</StructureMap>

It is quite obvious what this configuration file does: Inside the UserManager assembly, there is UserManager type which implements the IUserManager interface. Also, inside the same assembly, there is a UserProvider type which implements the IUserProvider interface. In both cases, we define the scope as Singleton so that StructureMap container will construct the type instances only once.

The very simple DefaultInstance based configuration is not suitable if multiple Plugins implementing the same interface. You can see a more complex (but more powerful) configuration file content with PluginFamily, Plugin and Instance elements in this blog post.

Attribute based implementation

For those (like myself) who are not so keen on writing XML configuration files, StructureMap provides another way of defining IoC container components. Instead of reading values defined in a configuration file, StructureMap performs reflective attribute inspection of the given assemblies and registers all interfaces decorated with [PluginFamilyAttribute] and all the types decorated with [PluggableAttribute].

The end result of either the configuration file or the attribute inspection is the same: StructureMap IoC container gets all the necessary mapping information.

Let’s take a quick look at an example of IUserProvider and UserProvider (a link to complete example is at the bottom of this post).

Marking an interface as PluginFamily looks like this:

using System.Collections.Generic;
using StructureMap;

namespace Example.UserManager
{
    [PluginFamily("userProviderService")]
    public interface IUserProvider
    {
        IList<User> GetUserCollection(string userName);
    }

I’ve decorated IUserProvider with a PluginFamily attribute specifying that the Plugin with key userProviderService is the default implementation.

And this is how the Plugin would be defined:

sing System.Collections.Generic;
using StructureMap;

namespace Example.UserManager
{
    [Pluggable("userProviderService")]
    public class UserProvider : IUserProvider
    {
        public IList<User> GetUserCollection(string userName)
        {
            // return something from DB
        }
    }
}

I’ve decorated the type which implements the interface (previously defined as PluginFamily) with the Plugin attribute, and provided a concrete lookup key for this implementation. As the key value is the same one used in the definition of the PluginFamily, UserProvider will be instantiated when the StructureMap retreival method is called (unless the key name of another desired plugin were provided to the retrieval method).

Now that we have the appropriate services and types decorated, all we need to do during the application startup is to tell StructureMap which assemblies it should inspect to collect services and concrete types. The code for doing that would look something like this:

            // turn off config file
            StructureMapConfiguration.UseDefaultStructureMapConfigFile=false;
            // collect components from the assembly containing IUserManager
            StructureMapConfiguration.ScanAssemblies()
                .IncludeAssemblyContainingType<IUserManager>();

After disabling the configuration file, I instruct StructureMap to scan the assembly containing IUserManager (which is UserManager in this example). As a result, StructureMap will register all the services and types exactly the same as the configuration file example.

Manual definition

In some cases, we might want to stay away from configuration file but adding attributes is not a viable option (e.g. we don’t own the source code or we don’t want to introduce a dependency to StructureMap). In these cases, we can take control from StructureMap and perform the appropriate container mappings on our own.

As an example, consider a test method that is supposed to test UserManager (which has a dependency on UserProvider) . My personal preference in writing tests is not to be depend on special – "test" configuration files, so instead I use a helper method for manual registration. The code is similar to this:

        private static void SetUpServiceLocator(I instance)
        {
            // 1. turn off configuration reading
            StructureMapConfiguration.UseDefaultStructureMapConfigFile = false;
            // 2. register a mapping between the service and type into the container
            StructureMapConfiguration.BuildInstancesOf(I);
            // 3. inject mocked instance
            ObjectFactory.InjectStub(typeof (I), instance);
        }

Method signature defines constraint that "T is I". The input parameter passed to this method is a concrete instance of a type which has to be retrieved later upon any request for "I" service.

In first line of the method StructureMap is instructed not raise an exception if the configuration file is  missing. After that, the service – type mapping is defined. Once the mapping definition is complete, StructureMap is instructed to register the provided instance so that the query to StructureMap for an instance of I will return that instance.

ObjectFactory

Regardless of how the StructureMap configuration is done (configuration file, attributes or manual approach), service location is the same. StructureMap already contains a built-in facade/service locator class, so there is no need to build those on your own (like I did in the Windsor example).

ObjectFactory has two major static methods used in service retrieval:

  • T ObjectFactory.GetInstance<T>();
  • T ObjectFactory.GetNamedInstance<T>(string concreteKey);

As you can tell from signatures, GetInstance method retrieves the default implementation of the service of type T, while GetNamedInstance allows you to pick a specific service implementation.

In this little example, we have a single service implementation so we use the ObjectFactory.GetInstance call:

using System;
using System.Collections.Generic;
using StructureMap;


namespace Example.UserManager
{
    [Pluggable("userManagerService")]
    public class UserManager : IUserManager
    {
        #region IUserManager Members
        public int NumberOfUsersActiveInLast10Days(string userName)
        {
            IUserProvider _userProvider
                = ObjectFactory.GetInstance<IUserProvider>();
            IList<User> userCollection
                = _userProvider.GetUserCollection(userName);

            int result = 0;
            foreach (User user in userCollection)
            {
                if (user.LastActivity > DateTime.Now.AddDays(-10))
                    result++;
            }
            return result;
        }
        #endregion
    }
}

 

The only interesting thing in this example (compared to the previous Windsor post) is that I have used StructureMap’s built-in SeviceLocator class ObjectFactory.GetInstance<IUserProvider>() to retrieve an instance of  UserProvider implementing the IUserProvider interface. In the Windsor example, I had to build the Service locator on my own.

Note: I am aware of the general concern about having opaque dependencies in this example and I plan to tackle that important question in separate post, so there’s no need to criticize me on that (at least not here 🙂 )

Writing unit tests using StructureMap DI framework

Writing tests with StructureMap is very simple and based on usage of InjectStub method already described in the manual configuration definition section above.

So, to test the business logic in NumberOfUsersActiveInLast10Days, I would need to mock the UserProvider dependency (to prevent DB calls that class does) and then just test the business logic. That would look something like this (same test as in previous blog posts):

	[Test]
        public void GetActiveUsers_TestCaseOfZeroUsers()
        {
            using (mockRepository.Record())
            {
                IUserProvider userProvider
                    = mockRepository.DynamicMock();
                Expect.Call(userProvider.GetUserCollection(null))
                    .IgnoreArguments()
                    .Return(new List());

                SetUpServiceLocator(userProvider);
            }
            using (mockRepository.Playback())
            {
                IUserManager _userManager = new UserManager();
                int count = _userManager.NumberOfUsersActiveInLast10Days("M");
                Assert.IsTrue(count == 0);
            }
        }

Interesting aspects of this test are:

  • Usage of new explicit Record/Playback model of writing tests using RhinoMocks (previous Windsor post was based on implicit recording model).
  • The first two commands are an example of using RhinoMocks to create a mocked instance of a given interface and to state required behavior for this test (there are no users retrieved from database).
  • The injection of the mock to the StructureMap IoC container is performed by the SetUpServiceLocator method (described above).

What’s next?

The purpose of these DFT blog posts is just to give a How-To quick start. To get more information on StructureMap, I recommend the following links:

Source code of the small example presented in this post can be found here

[edited by cbeauvais]

Advertisements

Posted on February 25, 2008, in Uncategorized. Bookmark the permalink. 2 Comments.

  1. I have an issue with your dependency on a concrete class (UserProvider) for your unit testing. Even though you are not using an instance of this class anywhere, it must exist for your code to compile. Is there a cleaner way of doing this with StructureMap? Seems to me that a unit testing project shouldn’t have an explicit dependency on a concrete data provider class (even if it is just dependent on its name).

  2. Randy,
    I agree it stinks but the main problem I had with SM is lack of documentation so that was the best I could come up  (and I switch to MS Unity couple a days after so never revisit this post)
    I corrected  the example (in fact it was so trivial I don’t know how I miss that first time) not to have dependency any more
    Thanks for the comment,
    Nikola

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: