我使用Specflow和WatiN进行了一些验收测试,但不确定在哪里为我的IOC容器(SimpleServiceLocator)设置注册。
在我的网站上,注册是我的global.asax.
在我的测试项目中,我尝试使用等代码从[BeforeScenario]方法设置它们
var container = new SimpleServiceLocator();
container.Register<ISitecoreLookupAccessor>(
() => new SitecoreLookupAccessor());
Microsoft.Practices.ServiceLocation.ServiceLocator
.SetLocatorProvider(() => container);
我在我的应用程序项目中使用获得了一个对象实例
ISitecoreLookupAccessor accessor =
ServiceLocator.Current.GetInstance<ISitecoreLookupAccessor>();
但是我得到一个错误"Object reference not set to a instance of a Object。"作为ServiceLocator.Current为null。。。
Global.asax是特定于ASP.NET的,不会在您的测试项目中运行,因为您的测试运行者无法知道它甚至应该考虑他们可能是Global.asax:-)的可能性
换句话说,为了能够使用ServiceLocator.Current
,应该使用该测试项目的有效容器来调用ServiceLocator.SetLocatorProvider
。使用MSTest时,有一个AssemblyInitializeAttribute可用于修饰方法。在这种情况下,MSTest将在执行该程序集中的任何测试方法之前运行该方法。其他测试运行者有不同的机制来实现这一点。
但是,与其在测试项目中配置公共服务定位器,不如防止在测试中完全使用它。相反,将被测类的所有依赖项注入其构造函数中,并在每个测试的设置阶段进行注入(为了方便起见,您可以将被测对象的构造重构为一个特殊的工厂方法)。防止从测试中的类(或应用程序中的任何类)中调用ServiceLocator
。这样就不需要在测试项目中使用ServiceLocator
。这将使编写测试变得更加容易,因为您不必在测试程序集中维护DI配置(对于多个测试项目,您将拥有多个DI配置)。我走了这条路,我的测试DI配置变得非常复杂,尤其是因为我必须让我的测试运行器并行运行我的测试,这意味着我必须注入线程安全的mock和stub(太可怕了!)。但是,即使没有并行运行的测试,维护测试DI配置也是相当可怕的。