Unity and dynamic mocks.

Apr 21, 2008 at 3:14 PM
Edited Apr 21, 2008 at 3:19 PM
We have an ordinary n-tier application with the usual DataServices layer, BusinessServices layer, Process Logic layer and Presentation layer. We want to be as decoupled as possible so we have gone for the following architecture

UI –uses-> Process Logic –uses-> BusinessServices –uses-> DataServices –accesses-> Database

An example class within the DataService layer

public class AuditDataService : IAuditDataService
{
public long InsertAuditRecord(string auditDescription, IDbTransaction transaction)
{
return 1;
}
}

public interface IAuditDataService
{
long InsertAuditRecord(string auditDescription, IDbTransaction transaction);
}

An example class within the BusinessService layer

public class ContractBusinessService : IContractBusinessService
{
private IContractDataService contractDataService;
private IAuditDataService auditDataService;

public ContractBusinessService(
IContractDataService contractDataService,
IAuditDataService auditDataService)
{
this.contractDataService = contractDataService;
this.auditDataService = auditDataService;
}

public Contract GetContract(long id)
{
using (IDbTransaction transaction = Database.CreateTransaction())
{
Contract entity = this.contractDataService.SelectContract(id, transaction);

this.auditDataService.InsertAuditRecord(
"Retrieved contract with ID " + id.ToString(), transaction);

return entity;
}
}
}

public interface IContractBusinessService
{
Contract GetContract(long id);
}

The process logic uses an IoC Container to resolve the dependencies at runtime as follows

UnityContainer container = new UnityContainer();
container
.RegisterType<IContractBusinessService, ContractBusinessService>(new ContainerControlledLifetimeManager())
.RegisterType<IContractDataService, ContractDataService>(new ContainerControlledLifetimeManager())
.RegisterType<IAuditDataService, AuditDataService>(new ContainerControlledLifetimeManager());

Contract contract = container.Resolve<IContractBusinessService>().GetContract(1);

We would rather do all of this in a configuration file, so we use the following code to set the container up

IUnityContainer container = new UnityContainer();
UnityConfigurationSection section
= (UnityConfigurationSection)ConfigurationManager.GetSection("unity");
section.Containers"containerOne".Configure(container);

Again this works great. The problem comes when I try to combine what I have so far with unit testing and mock objects. If I do it in code, I can register a mock object against an interface as follows

MockRepository mocks = new MockRepository();
IContractDataService dataServiceMock = mocks.CreateMock<IContractDataService>();
container.RegisterInstance<IContractDataService>(dataServiceMock);

However I do not want to have to setup the container through code every time. I want to find a way to re-use the configuration file of the main application. The problem is that this configuration file contains registration information for all the interfaces, even for the ones that a unit test may need to mock. Unfortunately there is no “UnRegisterType” so after the container has been setup using the configuration file, the above code that registers the mock does nothing and when the dependency is resolved the concrete type is instantiated rather than using the Mock object.

Any ideas as to how I can re-use the main application’s configuration file and still be able to mock specific interfaces in each unit test with minimum overhead would be much appreciated.

Thanks in advance,

Angelos
Apr 21, 2008 at 3:25 PM

Create a child container containing your mock objects and use the child container to resolve.


AngelosP wrote:
We have an ordinary n-tier application with the usual DataServices layer, BusinessServices layer, Process Logic layer and Presentation layer. We want to be as decoupled as possible so we have gone for the following architecture

UI –uses-> Process Logic –uses-> BusinessServices –uses-> DataServices –accesses-> Database

An example class within the DataService layer

public class AuditDataService : IAuditDataService
{
public long InsertAuditRecord(string auditDescription, IDbTransaction transaction)
{
return 1;
}
}

public interface IAuditDataService
{
long InsertAuditRecord(string auditDescription, IDbTransaction transaction);
}

An example class within the BusinessService layer

public class ContractBusinessService : IContractBusinessService
{
private IContractDataService contractDataService;
private IAuditDataService auditDataService;

public ContractBusinessService(
IContractDataService contractDataService,
IAuditDataService auditDataService)
{
this.contractDataService = contractDataService;
this.auditDataService = auditDataService;
}

public Contract GetContract(long id)
{
using (IDbTransaction transaction = Database.CreateTransaction())
{
Contract entity = this.contractDataService.SelectContract(id, transaction);

this.auditDataService.InsertAuditRecord(
"Retrieved contract with ID " + id.ToString(), transaction);

return entity;
}
}
}

public interface IContractBusinessService
{
Contract GetContract(long id);
}

The process logic uses an IoC Container to resolve the dependencies at runtime as follows

UnityContainer container = new UnityContainer();
container
.RegisterType<IContractBusinessService, ContractBusinessService>(new ContainerControlledLifetimeManager())
.RegisterType<IContractDataService, ContractDataService>(new ContainerControlledLifetimeManager())
.RegisterType<IAuditDataService, AuditDataService>(new ContainerControlledLifetimeManager());

Contract contract = container.Resolve<IContractBusinessService>().GetContract(1);

We would rather do all of this in a configuration file, so we use the following code to set the container up

IUnityContainer container = new UnityContainer();
UnityConfigurationSection section
= (UnityConfigurationSection)ConfigurationManager.GetSection("unity");
section.Containers"containerOne".Configure(container);

Again this works great. The problem comes when I try to combine what I have so far with unit testing and mock objects. If I do it in code, I can register a mock object against an interface as follows

MockRepository mocks = new MockRepository();
IContractDataService dataServiceMock = mocks.CreateMock<IContractDataService>();
container.RegisterInstance<IContractDataService>(dataServiceMock);

However I do not want to have to setup the container through code every time. I want to find a way to re-use the configuration file of the main application. The problem is that this configuration file contains registration information for all the interfaces, even for the ones that a unit test may need to mock. Unfortunately there is no “UnRegisterType” so after the container has been setup using the configuration file, the above code that registers the mock does nothing and when the dependency is resolved the concrete type is instantiated rather than using the Mock object.

Any ideas as to how I can re-use the main application’s configuration file and still be able to mock specific interfaces in each unit test with minimum overhead would be much appreciated.

Thanks in advance,

Angelos

Apr 21, 2008 at 3:30 PM
I tried that and it still doesn't work as RegisterType in the parent container appears to take precedence over RegisterInstance in the child container.
Apr 21, 2008 at 3:42 PM

The unity docs state that resolution walks up the tree, not down.

            IUnityContainer rootContainer = new UnityContainer();
            rootContainer.RegisterType<ILogger, TraceLogger>();
 
            IUnityContainer container = rootContainer.CreateChildContainer();
            container.RegisterType<ILogger, MockLogger>();
 
            // .. more code
 
            ILogger logger = container.Resolve<ILogger>();



AngelosP wrote:
I tried that and it still doesn't work as RegisterType in the parent container appears to take precedence over RegisterInstance in the child container.

Apr 21, 2008 at 4:01 PM
I have managed to replicate the behavior I'm after by making a slight modification to the code Roy Osherove has posted here

http://weblogs.asp.net/rosherove/archive/2008/04/14/creating-a-automockingcontainer-with-microsoft-unity-pretty-darn-simple.aspx?CommentPosted=true#commentmessage

I explain the change I made in the comments of that blog post.
Apr 21, 2008 at 4:09 PM


pbolduc wrote:

The unity docs state that resolution walks up the tree, not down.

            IUnityContainer rootContainer = new UnityContainer();
            rootContainer.RegisterType<ILogger, TraceLogger>();
 
            IUnityContainer container = rootContainer.CreateChildContainer();
            container.RegisterType<ILogger, MockLogger>();
 
            // .. more code
 
            ILogger logger = container.Resolve<ILogger>();



AngelosP wrote:
I tried that and it still doesn't work as RegisterType in the parent container appears to take precedence over RegisterInstance in the child container.



What you are saying is correct, whoever there is a twist. In the parent container the build up of the container from the configuration file uses RegisterType. When I register my mock in the child container I use RegisterInstance. In this scenario, RegisterType in the parent container seems to take precedence for some reason. I am not sure if that is by design or just a bug.
Apr 21, 2008 at 5:00 PM
Edited Apr 21, 2008 at 5:26 PM
I think you've found a bug.

Here's what I think is happening. Type mapping occurs before instances are resolved. This happens regardless of config file or API, so I'll use the API for compactness in the examples.

So, in a code sequence like this:

IUnityContainer parent = new UnityContainer()
  .RegisterType<IFoo, RealFoo>();
 
IUnityContainer child = parent.CreateChildContainer()
  .RegisterInstance<IFoo>(new MockFoo());
 
IFoo result = child.Resolve<IFoo>();

What happens is first thing, it looks for a type mapping for IFoo. It doesn't find one in the child, so it goes to the parent, and finds the mapping IFoo -> RealFoo. Next, it goes looking for instances, but at that point it's looking for RealFoo, not IFoo, so the instance in the child gets skipped.

Oops! Sorry about that. I'll make sure it's fixed in the next release. In the meantime, if you do:

child.RegisterType<IFoo, IFoo>();

That'll override the parent's mapping and should work around the problem.

Thanks for finding this!

-Chris
Apr 21, 2008 at 9:15 PM
Thanks Chris, your explanation describes percicely what I'm experiencing and your workaround is what I had to do to get things working.

Keep up the good work, it's much appreciated.

Angelos