Skip to content

Instantly share code, notes, and snippets.

@aggieben
Last active June 5, 2020 15:21
Show Gist options
  • Save aggieben/a389b01b7ba637a265299c1b2f9337d0 to your computer and use it in GitHub Desktop.
Save aggieben/a389b01b7ba637a265299c1b2f9337d0 to your computer and use it in GitHub Desktop.
Testing StructureMap child containers and Injection
<Query Kind="Program">
<NuGetReference>FluentAssertions</NuGetReference>
<NuGetReference>NSubstitute</NuGetReference>
<NuGetReference>NUnit</NuGetReference>
<NuGetReference>structuremap</NuGetReference>
<Namespace>FluentAssertions</Namespace>
<Namespace>NSubstitute</Namespace>
<Namespace>NUnit</Namespace>
<Namespace>NUnit.Framework</Namespace>
<Namespace>StructureMap</Namespace>
</Query>
void Main()
{
// setup according to registry below. That is:
// IThingRepository requires an IFoo.
// IFooProvider requires an IThingRepository (which depends on IFoo)
// IFoo is implemented by Foo, but decorated by CachedFoo, which also depends on IBar
// so the full dependency chain is like this, top to bottom:
// IFooProvider
// => IThingRepository
// => IFoo
// => CachedFoo (decoration)
// => IBar
// set up the container
var container = new Container(cfg => cfg.IncludeRegistry<FooRegistry>());
// instantiate the singleton IThingRepository (which should also instantiate IFoo, CachedFoo, and IBar)
_ = container.GetInstance<IThingRepository>();
// get the IFooProvider and check that it's getting a CachedFoo decorator from the IBasketRepository
// and that the IFoo being held by CachedFoo is of type Foo
var fooProvider = container.GetInstance<IFooProvider>();
var cachedFoo = fooProvider.CreateFoo();
cachedFoo.Should().BeOfType<CachedFoo>();
((CachedFoo)cachedFoo).InnerFoo.Should().BeOfType<Foo>();
// build a child container and eject the IFooProvider singleton
container.Model.For<IFoo>().EjectAndRemoveAll();
var child = container.CreateChildContainer();
child.Model.For<IFooProvider>().Default.EjectObject();
child.Model.For<IThingRepository>().Default.EjectObject();
child.Model.For<IFoo>().EjectAndRemoveAll();
child.Invoking(c => c.GetInstance<IFoo>()).Should().Throw<Exception>();
// add a substitute Foo
var substituteFoo = Substitute.For<IFoo>();
child.Inject<IFoo>(substituteFoo);
// ensure we can request the fake foo
var requestedFoo = child.GetInstance<IFoo>();
requestedFoo.Should().BeSameAs(substituteFoo);
// get an instance of the FooProvider (should become the singleton)
// assert that the inner foo should be the FakeFoo we just injected
var fooProvider2 = child.GetInstance<IFooProvider>();
var cached2 = fooProvider2.CreateFoo() as CachedFoo;
Assert.IsNotInstanceOf<Foo>(cached2.InnerFoo);
var provider2 = child.GetInstance<IFooProvider>();
Assert.IsNotInstanceOf<FakeFoo>(fooProvider.CreateFoo());
}
public class FooRegistry : Registry
{
public FooRegistry()
{
For<IThingRepository>().Singleton().Use<ThingRepository>();
For<IFooProvider>().Singleton().Use<FooProvider>();
For<IBar>().Singleton().Use<Bar>();
For<IFoo>().Singleton().Use<Foo>()
.DecorateWith((ctx, inner) => new CachedFoo(inner, ctx.GetInstance<IBar>()));
}
}
public interface IFooProvider { IFoo CreateFoo(); }
public class FooProvider : IFooProvider
{
private readonly IThingRepository _repo;
public FooProvider(IThingRepository repo)
{
_repo = repo;
}
public IFoo CreateFoo()
{
return _repo.Foo;
}
}
public interface IThingRepository { IFoo Foo { get; } }
public class ThingRepository : IThingRepository
{
public ThingRepository(IFoo foo)
{
Foo = foo;
}
public IFoo Foo { get; }
}
public interface IFoo { }
public interface IBar { }
public class Foo : IFoo { }
public class Bar : IBar { }
public class CachedFoo : IFoo
{
public CachedFoo(IFoo innerFoo, IBar bar) { InnerFoo = innerFoo; }
public IFoo InnerFoo { get; }
}
public class FakeFoo : IFoo { }
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment