在我的测试中,我设置了一个 autofac 容器,它返回一些实际实现和一些模拟(数据库、外部系统)。
问题是,每次测试后我都会处理容器并创建一个新容器:
Autofac.IContainer.Dispose()
和Container = builder.Build();
已经注册的实例仍然存在。
如何重置容器,使其再次“像新的一样”?
我想要这样做的原因是 - 我想用另一个模拟实例替换一个模拟实例。它正在注册为 Singleton。
----编辑
感谢您的回答。我决定添加更多代码并描述我实际上想要实现的目标。但这实际上是另一个主题(可能已经回答了问题 - 单元测试 CQRS)。
我的应用程序包含静态 IContainer 属性:
public static IContainer Container { get; private set; }
每次测试执行后,我都会通过调用这两个方法再次创建它:
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);
}
和
TestDependencyProvider dependencyProvider = new TestDependencyProvider()
var builder = Compose(new[] { dependencyProvider });
Container = builder.Build();
TestDependencyProvider
为每个测试创建并包含 moqed 实例。它注册这些模拟和 x.GetDependencies()
使用原始容器注册,即 container.RegisterAssemblyTypes(Assembly.GetExecutingAssembly()).AsClosedTypesOf(typeof(IAggregateBusinessRuleForEvent<,>));
我最感兴趣的类型是 IAggregateBusinessRuleForEvent<,>)
的实现之一。
public class RuleA: IAggregateBusinessRuleForEvent<AEvent, Something>
{
private readonly IDependency _dependency;
public RejectCompanyNameRule(IDependency dependency)
{
_dependency = dependency;
}
}
所以即使我再次创建这个容器 RuleA
仍然在那里,我的所有测试都使用具有相同 _dependency
的相同实例:/
仍然不完全清楚为什么代码看起来像它的样子,我试图通过添加测试来理解它......
--------编辑2
按照吉米的建议,我使用 Update
实现了一个示例我
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();
}
结果是:
Hello
A
Hello
A
最佳答案
默认情况下,Autofac 会用后续注册覆盖之前的注册。这意味着除了使用新实例更新容器之外,您无需执行任何特殊操作:
var builder = new ContainerBuilder();
builder.RegisterInstance(new Sample("A")).SingleInstance();
var container = builder.Build();
var sample = container.Resolve<Sample>();
// do your test
...
// new test using same container
var updater = new ContainerBuilder();
updater.RegisterInstance(new Sample("B")).SingleInstance();
updater.Update(container); // overwrites existing registrations
var sample = container.Resolve<Sample>(); // returns "B"
关于unit-testing - 如何重置 autofac 容器?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18742941/