Last active
June 5, 2020 15:21
-
-
Save aggieben/a389b01b7ba637a265299c1b2f9337d0 to your computer and use it in GitHub Desktop.
Testing StructureMap child containers and Injection
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<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