我想在SpecFlow测试运行开始时创建一个NHibernate会话工厂,然后在单独的步骤定义中访问它以在其上调用OpenSession()。
似乎[BeforeTestRun]
钩子是设置会话工厂的最佳位置。但是我很难看到如何存储会话工厂,然后在特定的步骤定义中检索它(很可能是Background
部分的一部分),以便获得会话并插入一些数据。
我尝试使用SpecFlow容器,如下所示:
[Binding]
public class NhDataSupport
{
private readonly IObjectContainer objectContainer;
public NhDataSupport(IObjectContainer objectContainer)
{
this.objectContainer = objectContainer;
}
[BeforeTestRun]
public void InitializeSessionFactory()
{
var sessionFactory = Fluently.Configure()
.Database(MsSqlConfiguration.MsSql2012.ConnectionString(c => c.FromConnectionStringWithKey("SqlServerDataTesting")))
.Mappings(cfg =>
cfg.FluentMappings.AddFromAssemblyOf<HostMap>()
)
.BuildSessionFactory();
objectContainer.RegisterInstanceAs<ISessionFactory>(sessionFactory);
}
}
...以便其他[Binding]
类可以通过构造函数注入传递给会话工厂,我希望如此。但这得到了
System.Reflection.TargetException,非静态方法需要一个目标。
我猜这是因为(正如我从SpecFlow docs中学到的),应用的方法[BeforeTestRun]
必须是静态的。
有没有办法实现这一点,配置SessionFactory一次,但从其他Binding类调用OpenSession?我不想为每个场景构建会话工厂,因为这是一项昂贵的操作。
答案 0 :(得分:2)
以下作品。
[Binding]
- 带注释的类上使用静态字段。 [BeforeTestRun]
中,完成工作(在我的案例中构建SessionFactory
)并将结果分配给静态字段。 [BeforeScenario]
中,使用容器注册静态字段实例。不确定它是否是最佳做法,但确实有效。
[Binding]
public class DataHooks
{
private readonly IObjectContainer objectContainer;
private static ISessionFactory sessionFactory;
public DataHooks(IObjectContainer objectContainer)
{
this.objectContainer = objectContainer;
}
[BeforeTestRun]
public static void SetupNhibernateSessionFactory()
{
sessionFactory = Fluently.Configure()
.Database(MsSqlConfiguration.MsSql2012.ConnectionString(c => c.FromConnectionStringWithKey("SqlServerDataTesting")))
.Mappings(cfg =>
cfg.FluentMappings.AddFromAssemblyOf<HostMap>()
)
.BuildSessionFactory();
}
[BeforeScenario]
public void BeforeScenario()
{
objectContainer.RegisterInstanceAs<ISessionFactory>(sessionFactory);
}
}
然后,会话工厂可以通过构造函数注入[Binding]
在任何ISessionFactory
- 带注释的类中使用。
答案 1 :(得分:2)
你可以这样做:
public class SessionFactoryHolder
{
private static ISessionFactory sessionFactory;
public static void SetupNhibernateSessionFactory()
{
sessionFactory = Fluently.Configure()
.Database(MsSqlConfiguration.MsSql2012.ConnectionString(c => c.FromConnectionStringWithKey("SqlServerDataTesting")))
.Mappings(cfg => cfg.FluentMappings.AddFromAssemblyOf<HostMap>() )
.BuildSessionFactory();
}
public ISessionFactory SessionFactory
{
get { return sessionFactory; }
}
}
[Binding]
public class Binding
{
[BeforeTestRun]
public static void SetupNhibernateSessionFactory()
{
SessionFactoryHolder.SetupNhibernateSessionFactory();
}
}
现在,当您让SpecFlow通过构造函数注入SessionFactoryHolder时,您可以访问SessionFactory。
它类似于@ngm解决方案,但您可以从SpecFlow获取“内部”IObjectContainer。
请参阅此处http://www.specflow.org/documentation/Context-Injection/了解有关SpecFlow中上下文注入的更多信息。
注意:代码由head编写,未尝试编译,因此可能存在拼写错误。
答案 2 :(得分:0)
虽然这不是NHibernate特有的,但我遇到了一个类似的问题,试图在API测试的整个测试运行期间保持授权。我最后使用[BeforeScenario]标签为我的休息客户端使用单例模式。虽然这个问题不是[BeforeTestRun],并且在每个场景之前仍然会注册对象,但客户端创建的次数仍然限制为一次。我想你可以对NHibernate应用类似的方法。
[Binding]
public class RestClientInjector
{
private readonly IObjectContainer objectContainer;
public RestClientInjector(IObjectContainer objectContainer)
{
this.objectContainer = objectContainer;
}
[BeforeScenario]
public void InitializeRestClient()
{
RestClient client = SingletonRestClient.getInstance();
objectContainer.RegisterInstanceAs<RestClient>(client);
}
// implelent singleton
public class SingletonRestClient
{
private static RestClient client = new RestClient();
private SingletonRestClient(IObjectContainer objectContainer) {}
public static RestClient getInstance()
{
return client;
}
}
}