Testklasse für generische Tests
Das Ziel dieses Musters ist es, durch vorgefertigte Tests eine Fachapplikation (Land) auf allgemeine Fehler hin zu untersuchen und diese über Tests abzudecken. Durch Tests mithilfe von NUnit lassen sich komplexere Prüfungen als durch die statische Musterprüfung durchführen. Zu diesen Tests gehört beispielsweise das Aufdrahten des DI-Containers der Server-Applikation oder das Testen von Repositories.
Design
Um in der Fachapplikation die generischen Tests anzuschließen, muss eine Klasse angelegt werden, die sich von der Basisklasse Generic<XY>TestBase
ableitet. Alle ausgeführten Tests sind dabei Unittests.
Implementierung
Zur Implementierung ist lediglich das Ableiten von der jeweiligen Basisklasse notwendig.
public sealed class GenericXYTests : GenericXYTestBase { }
Deaktivieren einer Prüfung
Um die Tests anzuschließen ist lediglich eine Ableitung von der Basisklasse notwendig. Möchte man einzelne Prüfungen für einen Typen deaktiveren, so ist das SuppressGenericTest
-Attribut zu verwenden,
[SuppressGenericTestAttribute(GenericXYTestBase.CheckXY)] // Hierdurch wird die Prüfung XY unterdrückt. public sealed class MyClassToCheck { }
Die im Attribut zu verwendende Konstante mit dem Namen des zu unterdrückenden Tests, befindet sich jeweils in der Basisklasse.
Repository-Tests (NHibernate)
Für Repositories nach Muster Objektpersistierung mit NHibernate für die Verwendung von NHibernate stehen aus dem Framework Basisklassen mit Tests zur Verfügung. Diese sollten in jeder Fachapplikation angeschlossen sein.
/// <summary> /// Anschluss in Schleupen.Land.Repositories. /// </summary> public sealed class GenericRepositoryTests : Schleupen.CS.PI.Framework.Persistence.Testing.NHibernate.GenericRepositoryTestBase { protected override Assembly Assembly => typeof(MyRepository).Assembly; // Assembly mit den Repositories protected override IConnectionInfoProvider ConnectionProvider => new ConfigurationFileConnectionInfoProvider(); }
Für Repositorys nach Muster Objektpersistierung mit NHibernate stehen Tests zur Verfügung, die die allgemeine Funktionalität sicherstellen sollen, z.B. wird das Mapping geprüft. Hierzu muss man sich von GenericRepositoryTestBase
ableiten. Die Basisklasse durchsucht dann die Assembly, in der Unterklasse definiert ist nach zu prüfenden Typen; in diesem Fall also Repositorys.
Auch diese so angebundenen Tests für NHibernate-Repositorys sind dann in der NUnit-GUI zu sehen.
Deaktivieren von Prüfungen
Falls bspw. Aggregate von den Prüfungen ausgeschlossen werden sollen, müssen z.B. Properties CheckCourseGrainedLockAggregates
und CheckValidatedAggregates
überschrieben werden, indem dort die Typen rausgefiltert werden.
Service-Tests (DI, Castle)
Es gibt auch einen generischen Test, der prüft, ob die WCF-Services per DI zusammengebaut werden können. Dazu sucht er alle Service-Interfaces und versucht damit, eine Instanz des jeweiligen Services über Castle zu erzeugen:
/// <summary> /// Testet alle Services. /// </summary> internal sealed class MyGenericServiceTest : Schleupen.CS.PI.Framework.Testing.DependencyInjection.Castle.GenericServiceTestBase { protected override Assembly ServiceAssembly => typeof(SomeType).Assembly; protected override ContainerConfigurator ServiceConfigurator => new MyTransientWcfConfigurator(); protected override IEnumerable<System.Type> FilterTypesForGetImplementationOfInterface( IEnumerable<System.Type> serviceInterfaceTypes) { // ISomeService wird explizit ausgeschlossen return serviceInterfaceTypes.Except(new[] { typeof(ISomeService) }); } private sealed class MyTransientWcfConfigurator : MyExistingWcfConfigurator { protected override void SetupLifestyle(Assembly assembly, BasedOnDescriptor descriptor) { if (descriptor == null { throw new ArgumentNullException(nameof(descriptor)); } descriptor.LifestyleTransient(); // Hier den Lifestyle ändern. Siehe Anmerkung unten. } } }
Ab dem Framework in Version 3.3.0.0 muss der Konfigurator den Lifestyle der registrierten Komponenten des Frameworks auf Transient ändern. Der Standard aus dem Framework ist PerWcfRequest. Dies funktioniert im Kontext von Unittests nicht (im ServiceTestFixture (-> ComponentTest) bleibt es aber bei PerWcfRequest).
Soll eine Service-Schnittstelle vom Test ausgeschlossen werden, so kann dies durch das Attribut Schleupen.Framework.SuppressGenericTestAttribute
oder direkt im Code durch überschreiben der virtuellen Methode FilterTypesForGetImplementationOfInterface
erfolgen.
Sämtliche Services müssen getestet werden, ob diese durch Interceptoren gewrapped werden können.
Folgende Attribute müssen dazu auf true
gestellt werden
protected override bool PerformServiceImplementationMethodsCanBeInterceptedTest => true; protected override bool PerformServiceImplementationHasServiceBehaviorAttributeTest => true;
Um sicherzustellen, dass die Services überhaupt mit dem ErrorHandler-Attribut versehen sind, muss auch dies angeschaltet werden:
Folgendes Attribut muss dazu auf true gestellt werden:
protected override bool PerformServiceImplementationHasErrorHandlerBehaviorAttributeTest => true;
Assembler-Test
Für Assembler, die nach Muster Anschluss des Domänenmodells an die Service-Fassade erstellt wurden existieren ebenfalls automatisch generierte Tests.
internal sealed partial class GenericAssemblerTestBaseTest : GenericAssemblerTestBase { protected override Assembly Assembly => typeof(SomeType).Assembly; protected override IContainerConfigurator ContainerConfigurator => new MyTestConfigurator(); }
Erweiterungen
Zusätzlich zu den durch die Basisklasse bereitgestellten Tests können eigene Tests für fachapplikationsspezifische Prüfungen in der Unterklasse implementiert werden.
Stärken und Schwächen
Stärken
- Prüfung auf häufig auftretende Fehler
- Geringer Implementierungsaufwand
- Tests stehen allen Fachapplikationen zur Verfügung
Schwächen
- Eigentlicher Testcode befindet sich nicht in der Fachapplikation, daher kann es etwas aufwändiger sein, im Fehlerfall diesen zu verstehen