Ich möchte zu Beginn eines SpecFlow-Testlaufs einmal eine NHibernate-Sitzungsfactory erstellen und dann in einzelnen Schrittdefinitionen darauf zugreifen, um OpenSession () darauf aufzurufen.
Es scheint, als wäre ein [BeforeTestRun]
Hook der beste Ort, um die Session Factory einzurichten. Ich habe jedoch Schwierigkeiten zu sehen, wie ich die Sitzungsfactory speichern und dann in einer bestimmten Schrittdefinition (höchstwahrscheinlich Teil eines Background
- Abschnitts) abrufen kann, um eine Sitzung abzurufen und einige Daten einzufügen.
Ich habe versucht, den SpecFlow-Container wie folgt zu verwenden:
[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);
}
}
... damit andere [Binding]
Klassen per Konstruktorinjektion an die Session Factory übergeben werden konnten, hoffte ich. Aber das bekommt ein
System.Reflection.TargetException, Nicht statische Methode erfordert ein Ziel.
Ich vermute, das liegt daran, dass (wie ich aus den SpecFlow-Dokumenten gelernt habe) die Methode {{ X0}} muss statisch sein.
Gibt es eine Möglichkeit, dies zu erreichen, indem Sie die SessionFactory einmal konfigurieren, aber OpenSession von anderen Bindungsklassen darauf aufrufen? Ich möchte die Session Factory nicht für jedes Szenario erstellen, da dies eine teure Operation ist.
3 Antworten
Sie könnten so etwas tun:
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();
}
}
Jetzt können Sie auf die SessionFactory zugreifen, wenn Sie SpecFlow den SessionFactoryHolder über den Konstruktor injizieren lassen.
Es ähnelt der @ ngm-Lösung, Sie können jedoch sparen, um den "internen" IObjectContainer von SpecFlow zu erhalten.
Siehe hier http://www.specflow.org/documentation/Context-Injection/ Weitere Informationen zur Kontextinjektion in SpecFlow.
Hinweis: Code, der von head geschrieben wurde und nicht versucht wurde zu kompilieren, daher kann es zu Tippfehlern kommen.
Folgendes funktioniert.
- Verwenden Sie ein statisches Feld für eine nicht statische
[Binding]
- kommentierte Klasse. - Führen Sie in
[BeforeTestRun]
die Arbeit aus (in meinem Fall das Erstellen vonSessionFactory
) und weisen Sie das Ergebnis dem statischen Feld zu. - Registrieren Sie in
[BeforeScenario]
die statische Feldinstanz im Container.
Ich bin mir nicht sicher, ob es die beste Vorgehensweise ist, aber es funktioniert.
[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);
}
}
Die Session Factory ist dann in jeder [Binding]
- annotierten Klasse über die Konstruktorinjektion von ISessionFactory
verfügbar.
Obwohl dies nicht spezifisch für NHibernate ist, stieß ich auf ein ähnliches Problem, bei dem versucht wurde, die Autorisierung während eines gesamten Testlaufs von API-Tests aufrechtzuerhalten. Am Ende habe ich ein Singleton-Muster für meinen Rest-Client mit dem Tag [BeforeScenario] verwendet. Obwohl dies nicht [BeforeTestRun] ist, nach dem diese Frage gestellt wird, und das Objekt vor jedem Szenario weiterhin registriert wird, ist die Häufigkeit, mit der der Client erstellt wird, immer noch auf einmal beschränkt. Ich würde mir vorstellen, dass Sie einen ähnlichen Ansatz auf NHibernate anwenden könnten.
[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;
}
}
}
Verwandte Fragen
Neue Fragen
c#
C # (ausgesprochen "siehe scharf") ist eine statische Typisierungsprogrammiersprache mit mehreren Paradigmen, die von Microsoft entwickelt wurde. C # -Code zielt normalerweise auf die .NET-Tools und -Laufzeiten von Microsoft ab, zu denen unter anderem .NET Framework, .NET Core und Xamarin gehören. Verwenden Sie dieses Tag für Fragen zu Code, der in der formalen Spezifikation von C # oder C # geschrieben ist.