Unit testing and mocking the container Resolve method

2,927 views
Skip to first unread message

Steven Burman

unread,
Sep 19, 2010, 11:53:34 PM9/19/10
to Autofac
I am currently in the process of upgrading our application from
Autofac 1.x to 2.x and I have cleared most of the little hurdles I
came across.

However, one remaining issue has me beat.

In some existing tests we mock the process of creating an inner
container scope and then mock out some calls to the Resolve method.
These tests passed successfully previously.

My guess (could be totally wrong) is whilst the exposed api did not
change, the Resolve method is now an extension method which means I
now have the task of delving into the source code so I can mock the
'actual' calls to Resolve on my inner container.

Just wondering if this is the right path to go down? Have others
complained of this change? Or is it just me :(

Paul Stovell

unread,
Sep 20, 2010, 12:01:31 AM9/20/10
to aut...@googlegroups.com
Is it possible to avoid calling .Resolve and inject an Owned<T>/Func<T> instead?

Paul




--
You received this message because you are subscribed to the Google Groups "Autofac" group.
To post to this group, send email to aut...@googlegroups.com.
To unsubscribe from this group, send email to autofac+u...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/autofac?hl=en.




--
Paul Stovell

Steven Burman

unread,
Sep 20, 2010, 12:09:45 AM9/20/10
to Autofac
I don't think so in this instance, because the resolve is called
against the mocked inner container (ILifetimeScope); although I am
happy to be proven wrong.

My instinct was to use Owned<ILifetimeScope> which would give me
control over the lifetime's creation and disposal.

However, when I invoke this I am unsure what ILifetimeScope I will
receive. So then I thought maybe I could register ILifetimeScope as

builder.Register(c =>
c.Resolve<IContainer>.BeginLifetimeScope()).As<ILifetimeScope>().InstancePerDependancy();

At this point I began cowering in fear and reverted to the foetal
position.

It might work yet. Spike in progress.


On Sep 20, 2:01 pm, Paul Stovell <p...@paulstovell.com> wrote:
> Is it possible to avoid calling .Resolve and inject an Owned<T>/Func<T>
> instead?
>
> Paul
>
> On Mon, Sep 20, 2010 at 1:53 PM, Steven Burman <steven.bur...@gmail.com>wrote:
>
>
>
> > I am currently in the process of upgrading our application from
> > Autofac 1.x to 2.x and I have cleared most of the little hurdles I
> > came across.
>
> > However, one remaining issue has me beat.
>
> > In some existing tests we mock the process of creating an inner
> > container scope and then mock out some calls to the Resolve method.
> > These tests passed successfully previously.
>
> > My guess (could be totally wrong) is whilst the exposed api did not
> > change, the Resolve method is now an extension method which means I
> > now have the task of delving into the source code so I can mock the
> > 'actual' calls to Resolve on my inner container.
>
> > Just wondering if this is the right path to go down? Have others
> > complained of this change? Or is it just me :(
>
> > --
> > You received this message because you are subscribed to the Google Groups
> > "Autofac" group.
> > To post to this group, send email to aut...@googlegroups.com.
> > To unsubscribe from this group, send email to
> > autofac+u...@googlegroups.com<autofac%2Bunsu...@googlegroups.com>
> > .

Steven Burman

unread,
Sep 20, 2010, 1:13:58 AM9/20/10
to Autofac
After re-reading I realise I have explained myself poorly. So, let the
setup code speak

container = MockRepository.GenerateMock<IContainer>();
scope = MockRepository.GenerateMock<ILifetimeScope>();
scopeRepository =
MockRepository.GenerateMock<IRepository<AuditItem>>();
scopeTransaction =
MockRepository.GenerateMock<IDisposableTransaction>();

container.Expect(m => m.BeginLifetimeScope()).Return(scope);
scope.Expect(c =>
c.Resolve<IRepository<AuditItem>>()).Return(scopeRepository);<<<<=====FAIL_IS_HERE
scopeRepository.Expect(m =>
m.BeginTransaction()).Return(scopeTransaction);
scopeTransaction.Expect(m => m.Commit());

The intent is to test that the transaction is being committed from
within the inner scope. Previously all worked fine - now the setup
code fails on the line indicated.

I hope that makes it a bit clearer :)

Paul Stovell

unread,
Sep 20, 2010, 1:38:44 AM9/20/10
to aut...@googlegroups.com
What does the code under test look like? I tried to deduce it from the test setup - is it something like this?

public class Foo 
{
public Foo(IContainer container)
{
this.container = container;
}
public void DoWork()
{
using (var scope = container.BeginLifetimeScope())
var repo = scope.Resolve<IRepository<AuditItem>>();
using (var txn = repo.BeginTransaction())
{
// Do work
txn.Commit();
}
}
}

If so you could change it to:

public class Foo 
{
public Foo(Func<Owned<IRepository<AuditItem>>> repositoryLocator)
{
this.repositoryLocator = repositoryLocator;
}
public void DoWork()
{
using (var repo = repositoryLocator())
using (var txn = repo.Value.BeginTransaction())
{
// Do work
txn.Commit();
}
}
}

Which I *think* will have the same effect as the version that uses the container, without requiring you to mock the container (or pass a container around). You could then just mock the Owned<IRepository<>>. 

Paul



To unsubscribe from this group, send email to autofac+u...@googlegroups.com.

Steven Burman

unread,
Sep 20, 2010, 2:06:16 AM9/20/10
to Autofac
Spot on for the class under test. Well inferred, Sir.

It is now down to a scoping issue. I have read over the source for
OwnedInstanceRegistrationSource and it certainly appears to create a
new scope each time the 'owned' instance is resolved. This would be
the desired behaviour for me and would be a fantastic result.

If Sir Blumhardt could confirm this assumption I would be most
pleased.
> > <autofac%2Bunsu...@googlegroups.com<autofac%252Buns...@googlegroups.com>

Paul Stovell

unread,
Sep 20, 2010, 2:19:27 AM9/20/10
to aut...@googlegroups.com
The wiki page on Owned<T> suggests they are equivalent:


When A is created by the container, the Owned<B> that it depends upon will be created inside its own lifetime scope. When A is finished using the B, disposing the Owned<B> reference will end the lifetime scope that contains B. This means that all of B's non-shared, disposable dependencies will also be released.


Paul


To unsubscribe from this group, send email to autofac+u...@googlegroups.com.

Nicholas Blumhardt

unread,
Sep 20, 2010, 7:45:14 AM9/20/10
to aut...@googlegroups.com
Sorry about the lagging response - yes, they're equivalent; looks like a good improvement over the original code :)

Cheers,
Nick
Reply all
Reply to author
Forward
0 new messages