PhD*_*PhD 3 c# ioc-container autofac specflow
我正在尝试在我的组织中采用BDD,因为C#.Net是我们的主要开发模式,Specflow是我们对"任何黄瓜"的最佳选择.
但是,我过去曾是一名Spring爱好者,但在我的公司,我们正在将Autofac用于应用程序的各个部分.但是,我找不到任何解释"如何"的资源,可以使用Autofac"触发"Specflow的BDD测试并提供必要的依赖连接.
我计划让Autofac负责实例化,连接和执行所有内容而不是执行Specflow,并且让调用Autofac的方法遍布各处,即使用Autofac作为服务定位器而不是DI/IoC容器.甚至可以这样做,还是我以错误的方式看待它并且有更好的方法来实现同样的目标?或者我应该完全依赖Specflow的"内部容器"进行DI并完全忘记Autofac?
可能的方法:
优点缺点:
我不确定如何实现它们中的任何一个,如果最好让Specflow处理DI并忘记Autofac或让Autofac解雇所有内容或者是否存在中间地带?
当前的BDD设置:Specflow,Selenium/PhantomJS,Xunit.希望与Autofac结合使用.
Max*_*uez 10
我计划让Autofac负责实例化,连接和执行所有内容,而不是执行Specflow,并且让调用Autofac的方法无处不在.
Visual Studio或ReSharper(我假设你不想失去它).让Specflow全局实例化Autofac,它与其余代码的必要依赖关系相连.可能的步骤定义可能会使用Autofac作为工厂来获得他们需要的东西.
但这会导致在将两个库耦合在一起的步骤定义中对Autofac进行大量调用.
AutoFac直接调用's方法来解析Step Definition类中所需的类型.我会在基类中创建一个方法,或者将一个对象绑定到具有所述方法的specflow的迷你DI容器.我要做的是创建一个名为的服务定位器接口IServiceLocator(是的,我知道服务定位器是一个反模式)
public interface IServiceLocator
{
T Get<T>();
}
Run Code Online (Sandbox Code Playgroud)
然后我们将使用创建此接口的实现Autofac(请记住,您可以将其替换为另一个实现)
public class AutoFacServiceLocator: IServiceLocator
{
private readonly IContainer _container;
public AutoFacServiceLocator(IContainer container)
{
_container = container;
}
public T Get<T>()
{
//Here you add your resolution logic
}
}
Run Code Online (Sandbox Code Playgroud)
对于每一个场景中,我们需要的实例的事实IServiceLocator,我们希望能够通过得到它Specflow的Context Injection.
[Binding]
public class Hooks
{
private readonly IObjectContainer _objectContainer;
public Hooks(IObjectContainer objectContainer)
{
_objectContainer = objectContainer;
}
[BeforeScenario]
public void RegisterServiceLocator()
{
var container = CreateContainer();
var serviceLocator = new AutoFacServiceLocator(container);
_objectContainer.RegisterInstanceAs<IServiceLocator>(serviceLocator);
}
private IContainer CreateContainer() { /*Create your container*/}
}
Run Code Online (Sandbox Code Playgroud)
最后这是用法
[Binding]
public class Steps
{
private readonly IServiceLocator _serviceLocator;
public Steps(IServiceLocator serviceLocator)
{
_serviceLocator = serviceLocator;
}
[Given(@"I have entered (.*) into the calculator")]
public void GivenIHaveEnteredIntoTheCalculator(int p0)
{
Foo foo = _serviceLocator.Get<Foo>();
}
}
Run Code Online (Sandbox Code Playgroud)
更新:
travis-illig在下面的评论中说
如果您使用服务位置,请尝试使用CommonServiceLocator而不是创建自己的界面
我真的不认为有必要使用CommonServiceLocator.对服务定位器的调用应与控制器中的构造函数注入匹配,这意味着该方法应涵盖这些调用Get<T>().
引用 ctavares,其中一位CommonServiceLocator开发人员
我应该将此库用于我的应用程序吗?
通常,这个问题的答案是否定的.一旦你决定了一个适合你项目的容器,以一种可以切换容器的方式编写整个应用程序并没有太大的好处.对于必须适应其他生态系统并与其他库很好地兼容的库,它是一个重要的特性,但对于应用程序来说,额外的抽象层实际上并没有给你带来太多帮助.
CommonServiceLocator是为了图书馆和框架,因为博士的测试项目是他和他的团队,我不建议引入更多的依赖项.