如何 link Autofac 到单元测试
How to link Autofac to UnitTesting
在我的 Web API 中,我将 Autofac 链接为 IoC 容器,我是这样做的:
域级别
public class Autofac
{
protected ContainerBuilder Builder { get; set; }
public Autofac()
{
this.Builder = new ContainerBuilder();
}
public virtual IContainer Register()
{
// Register dependencies
SetUpRegistration(this.Builder);
// Build registration.
var container = this.Builder.Build();
// End
return container;
}
private static void SetUpRegistration(ContainerBuilder builder)
{
// === DATALAYER === //
// MyRepository
builder.RegisterType<MyRepository>()
.As<IMyRepository>()
.InstancePerLifetimeScope();
// === DOMAIN === //
// MyManager
builder.RegisterType<MyManager>()
.As<IMyManager>()
.InstancePerLifetimeScope();
}
}
网页API
public class Autofac : Domain.IoC.Autofac
{
public IContainer Register(HttpConfiguration config)
{
// Register your Web API controllers.
base.Builder.RegisterApiControllers(Assembly.GetExecutingAssembly());
// OPTIONAL: Register the Autofac filter provider.
base.Builder.RegisterWebApiFilterProvider(GlobalConfiguration.Configuration);
// Complete registration and get container instance.
var container = base.Register();
// Set the dependency resolver to be Autofac.
config.DependencyResolver = new AutofacWebApiDependencyResolver(container);
// Done.
return container;
}
}
如您所见,它继承自域的基础 class 并设置 Web API 特定配置。
用法
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
GlobalConfiguration.Configure(WebApiConfig.Register);
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
new IoC.Autofac().Register(GlobalConfiguration.Configuration);
}
如您所知,位于 global.asax。
问题
这适用于 Web API,但我不知道我需要做什么才能在 UnitTest 项目上下文中注册所有这些内容。
我的想法是,我将在 Web API 级别创建一个与 Autofac class 类似的实现,但使用模拟(完全忽略来自域的基础 class)。
有什么指点吗?
就我个人而言,我从来没有看到直接在单元测试中设置我的 IoC 容器的需要(而且我很难理解它的可行性或帮助)。
由于单元测试用于测试可以快速构建的逻辑代码段,因此很容易 运行 并且不需要太多(我主张不需要)tear-down。它不应该要求为 运行.
测试设置所有应用程序
请记住,您的单元测试只是测试通过系统的数据流,即您的 DomainManager
实际上会在您期望的时候调用 IRepository
。然后,您将对所有存储库进行单独测试 classes 以确定它们是否会正确添加到数据库等。
我不确定您是如何使用 DBContext
class 但作为包装器的示例,这就是它的样子。
interface IDBSetWrapper
{
object Add(object entity);
}
interface IDBContextWrapper
{
...
IDBSet Set(Type entityType);
...
}
class DBContextWrapper : IDBContextWrapper
{
private readonly DBContext context;
public DBContextWrapper()
{
context = new DBContext();
}
...
public IDBSet Set(Type entityType)
{
var dbSet = context.Set(entityType);
return new DBSetWrapper(dbSet);
}
...
}
内容不多,但我希望它能说明我所说的薄包装纸的意思。基本上包装器是 DBContext 并将在 class 中包含它的一个实例,当您请求包装器执行任何操作时将调用实际的 DBContext。
我已经展示了返回另一个对象(在本例中为 DBSet)时会发生什么,这也将包装在一个具有接口的单独对象中。这样您就可以轻松地从这个 class 中模拟 returns。
您现在可以更好地将这个新包装器添加到您的 IoC 中,因为它提供了一个接口。
需要注意的一件事是您将无法并且可能不希望测试包装器 class,在我看来,这没有什么意义。但之前我看到同事对这些 classes 进行了集成测试。
在我的 Web API 中,我将 Autofac 链接为 IoC 容器,我是这样做的:
域级别
public class Autofac
{
protected ContainerBuilder Builder { get; set; }
public Autofac()
{
this.Builder = new ContainerBuilder();
}
public virtual IContainer Register()
{
// Register dependencies
SetUpRegistration(this.Builder);
// Build registration.
var container = this.Builder.Build();
// End
return container;
}
private static void SetUpRegistration(ContainerBuilder builder)
{
// === DATALAYER === //
// MyRepository
builder.RegisterType<MyRepository>()
.As<IMyRepository>()
.InstancePerLifetimeScope();
// === DOMAIN === //
// MyManager
builder.RegisterType<MyManager>()
.As<IMyManager>()
.InstancePerLifetimeScope();
}
}
网页API
public class Autofac : Domain.IoC.Autofac
{
public IContainer Register(HttpConfiguration config)
{
// Register your Web API controllers.
base.Builder.RegisterApiControllers(Assembly.GetExecutingAssembly());
// OPTIONAL: Register the Autofac filter provider.
base.Builder.RegisterWebApiFilterProvider(GlobalConfiguration.Configuration);
// Complete registration and get container instance.
var container = base.Register();
// Set the dependency resolver to be Autofac.
config.DependencyResolver = new AutofacWebApiDependencyResolver(container);
// Done.
return container;
}
}
如您所见,它继承自域的基础 class 并设置 Web API 特定配置。
用法
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
GlobalConfiguration.Configure(WebApiConfig.Register);
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
new IoC.Autofac().Register(GlobalConfiguration.Configuration);
}
如您所知,位于 global.asax。
问题
这适用于 Web API,但我不知道我需要做什么才能在 UnitTest 项目上下文中注册所有这些内容。
我的想法是,我将在 Web API 级别创建一个与 Autofac class 类似的实现,但使用模拟(完全忽略来自域的基础 class)。
有什么指点吗?
就我个人而言,我从来没有看到直接在单元测试中设置我的 IoC 容器的需要(而且我很难理解它的可行性或帮助)。 由于单元测试用于测试可以快速构建的逻辑代码段,因此很容易 运行 并且不需要太多(我主张不需要)tear-down。它不应该要求为 运行.
测试设置所有应用程序请记住,您的单元测试只是测试通过系统的数据流,即您的 DomainManager
实际上会在您期望的时候调用 IRepository
。然后,您将对所有存储库进行单独测试 classes 以确定它们是否会正确添加到数据库等。
我不确定您是如何使用 DBContext
class 但作为包装器的示例,这就是它的样子。
interface IDBSetWrapper
{
object Add(object entity);
}
interface IDBContextWrapper
{
...
IDBSet Set(Type entityType);
...
}
class DBContextWrapper : IDBContextWrapper
{
private readonly DBContext context;
public DBContextWrapper()
{
context = new DBContext();
}
...
public IDBSet Set(Type entityType)
{
var dbSet = context.Set(entityType);
return new DBSetWrapper(dbSet);
}
...
}
内容不多,但我希望它能说明我所说的薄包装纸的意思。基本上包装器是 DBContext 并将在 class 中包含它的一个实例,当您请求包装器执行任何操作时将调用实际的 DBContext。 我已经展示了返回另一个对象(在本例中为 DBSet)时会发生什么,这也将包装在一个具有接口的单独对象中。这样您就可以轻松地从这个 class 中模拟 returns。
您现在可以更好地将这个新包装器添加到您的 IoC 中,因为它提供了一个接口。
需要注意的一件事是您将无法并且可能不希望测试包装器 class,在我看来,这没有什么意义。但之前我看到同事对这些 classes 进行了集成测试。