如何在 BeforeTestRun 中创建内容并在步骤定义中访问它
How to create something in BeforeTestRun and access it in step definitions
我想在 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, Non-static method requires a target.
我猜这是因为(正如我从 SpecFlow docs 中了解到的),应用 [BeforeTestRun]
的方法必须是静态的。
有没有办法实现这一点,配置 SessionFactory 一次,但从其他绑定中调用 OpenSession 类?我不想为每个场景构建会话工厂,因为这是一项昂贵的操作。
以下作品。
- 在 non-static
[Binding]
注释 class 上使用静态字段。
- 在
[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);
}
}
然后会话工厂可以通过 ISessionFactory
.
的构造函数注入在任何 [Binding]
注释的 class 中使用
你可以这样做:
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 获取 "internal" IObjectContainer。
有关 SpecFlow 中上下文注入的更多信息,请参阅此处 http://www.specflow.org/documentation/Context-Injection/。
注意:代码是head写的,没有尝试编译,所以可能会有错别字。
虽然这不是 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;
}
}
}
我想在 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, Non-static method requires a target.
我猜这是因为(正如我从 SpecFlow docs 中了解到的),应用 [BeforeTestRun]
的方法必须是静态的。
有没有办法实现这一点,配置 SessionFactory 一次,但从其他绑定中调用 OpenSession 类?我不想为每个场景构建会话工厂,因为这是一项昂贵的操作。
以下作品。
- 在 non-static
[Binding]
注释 class 上使用静态字段。 - 在
[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);
}
}
然后会话工厂可以通过 ISessionFactory
.
[Binding]
注释的 class 中使用
你可以这样做:
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 获取 "internal" IObjectContainer。
有关 SpecFlow 中上下文注入的更多信息,请参阅此处 http://www.specflow.org/documentation/Context-Injection/。
注意:代码是head写的,没有尝试编译,所以可能会有错别字。
虽然这不是 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;
}
}
}