In my tests I setup an autofac container, it returns some real implementation and some mocks (DB, external systems).
The problem is that after each test I Dispose the container and create a new one:
Autofac.IContainer.Dispose()
and Container = builder.Build();
The already registered instances are still there.
How can I reset the container so it would be 'like new' again?
The reason why I want to do is - I want to replace one mocked instance with another. It's being registered as Singleton.
---- EDIT
Thanks for the answers. I decided to add some more code and describe what actually I'm trying to achieve. But that is actually a topic for another (prabably already answered question - unit testing CQRS).
My app contains static IContainer property:
public static IContainer Container { get; private set; }
After each test execution I create it again by calling those two methods:
public static ContainerBuilder Compose(IEnumerable<DependencyProvider> dependencyProviders)
{
var collection = dependencyProviders as List<DependencyProvider> ?? dependencyProviders.ToList();
var included = new HashSet<DependencyProvider>(collection);
var includedTypes = new HashSet<Type>(collection.Select(x => x.GetType()));
var currentWorkingSet = new List<DependencyProvider>(collection);
while (true)
{
var candidates = currentWorkingSet.SelectMany(x => x.GetDependencies());
var typesToBeAdded = candidates.Where(x => !includedTypes.Contains(x)).Distinct().ToList();
if (typesToBeAdded.Any() == false)
break;
currentWorkingSet.Clear();
foreach (var type in typesToBeAdded)
{
includedTypes.Add(type);
var instance = CreateInstance(type);
included.Add(instance);
currentWorkingSet.Add(instance);
}
}
return BuildContainer(included);
}
and
TestDependencyProvider dependencyProvider = new TestDependencyProvider()
var builder = Compose(new[] { dependencyProvider });
Container = builder.Build();
The TestDependencyProvider
is created for each test and contains moqed instances. It registers those mocks and x.GetDependencies()
uses the original container registrations i.e. container.RegisterAssemblyTypes(Assembly.GetExecutingAssembly()).AsClosedTypesOf(typeof(IAggregateBusinessRuleForEvent<,>));
The type I'm mostly interested in is one of implementations of IAggregateBusinessRuleForEvent<,>)
.
public class RuleA: IAggregateBusinessRuleForEvent<AEvent, Something>
{
private readonly IDependency _dependency;
public RejectCompanyNameRule(IDependency dependency)
{
_dependency = dependency;
}
}
So even though I create this container again that RuleA
is still there and all of my test are using same instance with same _dependency
:/
It's still not entierly clear why code looks how it looks, I'm trying to understand it by adding tests...
------- EDIT 2
Following Jimmy's advice I've implemented a sample using Update
me
public interface IExample<T>
{
void Hello();
}
public interface IExampleDependecy
{
void SaySomething();
}
public class Example : IExample<string>
{
private IExampleDependecy _dependecy;
public Example(IExampleDependecy dependecy)
{
_dependecy = dependecy;
}
public void Hello()
{
Console.WriteLine("Hello");
_dependecy.SaySomething();
}
}
[TestMethod]
public void T()
{
// first test
var builder = new ContainerBuilder();
builder.RegisterAssemblyTypes(Assembly.GetExecutingAssembly()).AsClosedTypesOf(typeof(IExample<>));
var mockA = new Moq.Mock<IExampleDependecy>();
mockA.Setup(d => d.SaySomething()).Callback(() => Console.WriteLine("A"));
builder.RegisterInstance(mockA.Object).SingleInstance();
var container = builder.Build();
var sample1 = container.Resolve<IExample<string>>();
sample1.Hello();
// new test using same container
var updater = new ContainerBuilder();
builder.RegisterAssemblyTypes(Assembly.GetExecutingAssembly()).AsClosedTypesOf(typeof(IExample<>));
var mockB = new Moq.Mock<IExampleDependecy>();
mockB.Setup(d => d.SaySomething()).Callback(() => Console.WriteLine("B"));
builder.RegisterInstance(mockB.Object).SingleInstance();
updater.Update(container); // overwrites existing registrations
var sample2 = container.Resolve<IExample<string>>();
sample2.Hello();
}
and result is:
Hello
A
Hello
A