Design for testability – Transparent and opaque dependencies (part 8)

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

(In case you don’t know what IoC containers are, I advise you to take a peek at Part 4 of this series first before continuing  with this article.In case you are not familiar with Microsoft Unity IoC framework which I would be using in this post read part 7)

Intro

Before I start, I would like to recommend you to subscribe to Alt.NET mail list where you have daily top notch discussions about various ultra interesting subjects.
One of April subjects was Are Opaque Depencies Bad? (Mockist TDD’s effect on design) where you can see that some of very smart people were stating that Opaque dependencies are sometime acceptable compromise because they encapsulate complexity and the component dependency information we get anyhow are not that valuable.

IMHO that is wrong because of the reasons I would state in this post and which can be summarized as:

  • writing tests for components implementing opaque IoC style is much harder
  • transparent IoC helps identifying controls which “do too much” – in general the  one with very big number of dependencies are maybe candidate for investigating if there is SoC violation

Opaque dependencies

In most of code in the same example I was using in previous posts in design for testability series, I was writing code similar to this:

using System;
using System.Collections.Generic;
using Facade;

namespace Example.UserManager
{
    public class UserManager : IUserManager
    {
        #region IUserManager Members
        public int NumberOfUsersActiveInLast10Days(string userName)
        {
            IUserProvider userProvider=ServiceLocator.Retrieve<IUserProvider>() ;
            IList<User> userCollection = userProvider.GetUserCollection();
            int result = 0;
            foreach (User user in userCollection)
            {
                if (user.Name.StartsWith(userName)
                    && user.LastActivity > DateTime.Now.AddDays(-10))
                    result++;
            }
            return result;
        }
        #endregion
    }
}

In first line of my the NumberOfUsersActiveInLast10Days method, an instance of type implementing IUserProvider has been retrieved and then used it in next line to get list of all users.
Once the list of users would be retrieved from DAL provider class, method code iterates and filters out all of the users which name starts with given string and which were active in last 10 days.

As you can see the usage of service locator is “hidden” into the method code and invincible outside of that method.

In other words, if we would check out the code using that method 

using System;
using Example.UserManager;
using Facade;

namespace Driver
{
    internal class Program
    {
        private static void Main(string[] args)
        {
            UserManager userManager=new UserManager();
            int activeUserCount = userManager.NumberOfUsersActiveInLast10Days(”DB”);
            Console.WriteLine(activeUserCount);

            Console.ReadKey();
        }
    }
}

we wouldn’t get any clue that UserManager has any dependency on ServiceLocator and UserManagerProvider.

This style of implicit usage of IoC framework where IoC framework is embed directly into the members using it, is called opaque dependency injection.

According to my personal experience opaque style is something looking very appealing to people new to IoC because it is a way of implementing IoC with “nothing changed”, so usually it is considered as “acceptable compromise” 🙂

Testing the opaque dependencies

Let see why I found this opaque style bad on example of how making test for this NumberOfUsersActiveInLast10Days method would look.

The test I would write would have to verify that for no users in database which have username starting the with given string, program would return zero.

I am sitting in black box testing camp (no testing of private method and looking at the code being tested maximally discouraged)  so I usually start my tests writing the playback code

        [Test]
        public void GetActiveUsers_TestCaseOfZeroUsers_WouldReturnEmptyCollection()
        {
            using (mockRepository.Record())
            {
                // no clear idea what to mock here
            }
            using (mockRepository.Playback())
            {
                var userManager = new UserManager();
                int numberOfUsers= userManager.NumberOfUsersActiveInLast10Days(“X”);
                Assert.IsTrue(numberOfUsers == 0);
            }
        }

Well, as you can see after writing the playback code representing the ways how the code would be used, I don’t have clear idea what I should mock in record section so the test wouldn’t fail.

The only way how I can write the test is to run the test, get error

System.InvalidOperationException: The current type, Example.UserManager.IUserProvider, is an interface and cannot be constructed. Are you missing a type mapping?

then add code to record phase mocking that, run the test again, check out additional error messages etc.

Not  very pleasant and productive way to get the final test result which in case of opaque dependency looks like

        [Test]
        public void GetActiveUsers_TestCaseOfZeroUsers_WouldReturnEmptyCollection()
        {
            using (mockRepository.Record())
            {
                var userProvider = mockRepository.DynamicMock<IUserProvider>();
                Expect.Call(userProvider.GetUserCollection())
                    .Return(new List<User>());
                ServiceLocator.InjectStub(userProvider);

            }
            using (mockRepository.Playback())
            {
                var userManager = new UserManager();

                int numberOfUsers= userManager.NumberOfUsersActiveInLast10Days(“X”);
                Assert.IsTrue(numberOfUsers == 0);
            }
        }

Transparent dependencies

Transparent dependency injection style requires explicit definition of dependencies in class constructor, exposing clearly what are the dependency class has.

UserManager class written in this way would look like this

using System;
using System.Collections.Generic;
using Facade;

namespace Example.UserManager
{
    public class UserManager : IUserManager
    {
        private readonly IUserProvider _userProvider;

        public UserManager():this(ServiceLocator.Retrieve<IUserProvider>())
        { }

        internal UserManager(IUserProvider userProvider)
        {
            _userProvider = userProvider;
        }

        #region IUserManager Members
        public int NumberOfUsersActiveInLast10Days(string userName)
        {
            IList<User> userCollection = _userProvider.GetUserCollection();
            int result = 0;
            foreach (User user in userCollection)
            {
                if (user.Name.StartsWith(userName)
                    && user.LastActivity > DateTime.Now.AddDays(-10))
                    result++;
            }
            return result;
        }
        #endregion
    }
}

If we look at the NumberOfUsersActiveInLast10Days method we would see that ServiceLocator class is not been used nay more there. Method now uses userProvider field without knowing how the _userProvider field is been initialized.

We have also two constructors:

  • Internal constructor accepting the parameter of IUserProvider data type and store its value into the _userProvider field
  • Public default constructor not accepting any parameters but which uses the ServiceLocator to retrieve from IoC container service implementing the IUserProvider interface and then calling internal constructor passing that service to internal constructor parameter

“Dude, this is no transparent dependency…”

Usually examples I was finding on net wouldn’t look like the just given example. The internal constructor would become public and the current default constructor doing poor man dependency injection through ServiceLocator wouldn’t exist at all.

Their rationale is that the UserManager would always be constructed using IoC framework which would automatically perform the injection during the IoC container construction time.

In real enterprise development that is often not true because we could have in existing code base a lot of places doing already doing UserManager  mgr=new UserManager() (constructing without the usage of IoC) so that implicit IoC dependency injection  wouldn’t work for them.I guess also that updating all of the current code just to be able to serve the IoC framework wouldn’t be probably very high on “resource allocation list“ spreadsheet, so we could count on the fact that this “legacy” code would stay like it is now.

What I am doing in my approach is basically switching that implicit IoC dependency injection with explicit one. The major difference here is that I am basing my IoC class design on default constructor and not on some specialized one. That’s why when code construct the class, in both cases (using IoC or new keyword) the result is the same – automatic service resolution and dependency injection. In other words, all this would work with any legacy code using the UserManager class.

Another significant gain (IMHO) from my approach is that I am hiding the complexity from production code (only default constructor exposed) while still having the same IoC concepts in place.

After all, having class design “open for testing but closed for code noise” is the whole point of this DTF blog post series.

“Dude, this is transparent dependency, just it is V2” 🙂

Testing the transparent dependencies

Once we have our code restructured testing is much more easier and even possible without using the ServiceLocator at all.

Writing the test in this case would show me during the Playback definition that UserManager class have a constructor accepting the IUserProvider class which would lead me to the conclusion what I need to mock in order to have this test done without “run until not complaining” approach I described in opaque test example above.

So first we would add to AssemblyInfo.cs file of UserManager appropriate assembly attribute

[assembly: InternalsVisibleTo(&quot;UserManager.Test&quot;)]

After this User.Test assembly would  get access to UserManager internal constructor above so the test would look like this

        [Test]
        public void GetActiveUsers_TestCaseOfZeroUsers_WouldReturnEmptyCollection()
        {
            IUserProvider userProvider = mockRepository.DynamicMock<IUserProvider>();
            using (mockRepository.Record())
            {
                Expect.Call(userProvider.GetUserCollection())
                    .Return(new List<User>());
            }
            using (mockRepository.Playback())
            {
                var userManager = new UserManager(userProvider);

                int numberOfUsers= userManager.NumberOfUsersActiveInLast10Days(“X”);
                Assert.IsTrue(numberOfUsers == 0);
            }
        }

Couple of things to note in this example:

  • I am not using ServiceLocator at all for implementing this test.
  • I am using internal UserManager constructor to inject UserProvider mock.
  • While writing the line using the internal constructor I realized (from constructor signature) that I need mocked instance of IUserProvider (first line of the test method)

Conclusion

IMHO, using of transparent dependency significantly simplifies the test making. The approach here I presented (with internal constructor) is variation of standard implementation made to hide the complexity and remove the rope from the hands of TDD unskilled developers. Applying it could enable having a small “TDD core team” of people doing component level design and enabling IoC (with all of the benefits) and all other developers totally unaware of the IoC class design which should reduce training costs and increase IoC adoption chances in organizations not applying it.

What’s next?

My next blog post would be on how AutoMockingContainer (AMC) makes testing easier in cases we are using transparent  dependency injection style so in a sense with this blog post makes complete explanation on how to test IoC based components done with transparent dependency injection style

Source code of the examples (opaque and transparent) presented in this post can be found here

Advertisements

Posted on June 8, 2008, in Uncategorized. Bookmark the permalink. 4 Comments.

  1. What I still don’t get is the following:
    Suppose I am going to use the UserManager class from your 2nd example (the one having 2 ctors) in my project. Since you’ve made the 2nd ctor internal I cannot see it and this forces me to use the parameterless ctor. By doing so I get the exact problems you mentioned in your opaque sample. So how is this transparent for me? And what will happen if you make the 2nd ctor public and I pass null? What will happen if your UserManager requires another dependency in the near future? That will break my code because all this DI stuff is not based on contracts which IMHO is one of the most fundamental problems for using it in the first place.

  2. Nikola, great series, thanks.  When using IoC, there is a "soft" dependency instead of a "hard" dependency between projects.  How do you manage your project references in those cases?
    Take these projects for instance: UI, BSL, IDAL, SqlDAL, OracleDAL
    The BSL would need a hard dependency on IDAL to compile but nothing else.  At runtime, the UI project would need the SqlDAL or OracleDAL assemblies in the bin depending on which one was used.
    How do you manage these references? Post build events?
    Thanks.

  3. Patrick,
    great questions I’ve been asking myself last couple of months too
    I’ve just blogged the answers I got on them here
    blog.vuscode.com/…/dependency-injection-in-real-world.aspx

  4. Troy,
    In short:
    BSL should have only dependency on IDAL and during the runtime appropriate IDAL service contract implementation should be injected.
    Typically, you have two solutions to do that:
    a) Configuration based solution
    You would define in some .config file list of the types (services) implementing the IDAL interface (service contract) and assign each one of them some key. Then during the run time you would determine which key value you need and then the IoC container would (using a reflection) create you instance of the desired service.
    Upside of this approach: no need to reference anywhere concrete services.
    Downside: the fact you have to use config file.  
    b) Builder based solution
    You create separate Builder dll which reference assemblies containing IDAL, SqlDAL and OracleDAL. Then you create Bootstrap class with Init method doing something like
    If (someCondition)
      ServiceLocator.Register<IDAL, SqlDAL>()
    Else
      ServiceLocator.Register<IDAL, OracleDAL>()
    Then in your main assembly you reference the assembly containing the IDAL interface and whenever needed you just do ServiceLocator.Retrieve<IDAL>()
    This sounds like a nice example for Separate interface blog post so if this summary info won’t be enough for you stay tuned for that blog post where you would have code example and detail explanation
    HTH,
    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: