正在使用Autofac作为我的IoC容器的ASP.NET Web API 2中的项目。该项目托管在IIS上,在我的Autofac模块中,我使用以下方法扫描程序集:
var asm = BuildManager.GetReferencedAssemblies().Cast<Assembly>().ToArray();
为什么?
https://docs.autofac.org/en/latest/register/scanning.html#iis-hosted-web-applications
但是现在我们正在使用NUnit进行单元测试,在设置过程中,我注册了使用此方法的模块。现在,在运行测试时,我收到以下异常:
System.InvalidOperationException: 'This method cannot be called during the application's pre-start initialization phase.'
我理解为什么会有这个异常,但是我不知道如何使我的代码在测试和部署环境中工作。
NUnit的设置方法:
[TestFixture]
public abstract class ApplicationTestBase
{
[SetUp]
public override void Init()
{
var builder = new ContainerBuilder();
// If the class requires auto mapper mapping, initialize them
// We do this in order not to init them for every test => optimalisation!
if (GetType().GetCustomAttributes<RequiresAutoMapperMappingsAttribute>(false) != null)
{
builder.RegisterModule<AutoMapperModule>();
}
this.Container = builder.Build();
}
}
我是否需要为我的单元测试创建一个新的模块,或者还有其他方法吗?
AutoMapperTest
[RequiresAutoMapperMappings]
[TestFixture]
public class AutoMapperTests : ApplicationTestBase
{
[Test]
public void Assert_Valid_Mappings()
{
Mapper.AssertConfigurationIsValid();
}
}
更新
就像西里尔提到的那样:为什么在单元测试中需要Ioc?我去搜索了,实际上您不必在测试中使用Ioc。因此,我放弃了Ioc,并通过以下方式初始化了我的映射器配置:
Mapper.Initialize(configuration =>
{
var asm = AppDomain.CurrentDomain.GetAssemblies()
.Where(a => a.FullName.StartsWith("ProjectWebService."));
configuration.AddProfiles(asm);
});
答案 0 :(得分:0)
我建议将“如何加载程序集”逻辑与“执行程序集扫描和注册模块逻辑”分开。
现在我想您可以通过一种方法来完成所有这些工作。
public IContainer BuildContainer()
{
var asm = BuildManager.GetReferencedAssemblies().Cast<Assembly>().ToArray();
var builder = new ContainerBuilder();
builder.RegisterAssemblyTypes(asm);
var container = builder.Build();
}
不完全是,但是类似的东西-内联程序集的加载是直接使用的。
将其分开,以便可以交换该逻辑以进行测试。例如,考虑允许有选择地传递参数,以便您可以覆盖测试中的逻辑。
public IContainer BuildContainer(Func<IEnumerable<Assembly>> assemblyLoader = null)
{
IEnumerable<Assembly> asm = null;
if (assemblyLoader != null)
{
asm = assemblyLoader();
}
else
{
asm = BuildManager.GetReferencedAssemblies().Cast<Assembly>().ToArray();
}
var builder = new ContainerBuilder();
builder.RegisterAssemblyTypes(asm);
var container = builder.Build();
}
您的默认逻辑将按照您想要的方式工作,但是在测试中,您可以交换其他内容。
var container = BuildContainer(() => AppDomain.GetAssemblies());
有很多方法可以进行这种交换。从可以在某处设置的静态属性到可以在某处覆盖的虚拟方法,它可以是任何东西。关键是,通过分离程序集加载逻辑,可以使测试时行为正常运行,但仍使用您要遵循的注册行为。