Fixture für Testklasse erstellen
Dieses Muster soll den Entwurf von Fixture-Klassen dokumentieren. Dabei stellt ein Fixture die Testumgebung bereit.
Design
Das Fixture hat eine 1:1-Beziehung zu der eigentlichen Testklasse. Außerdem kann das Fixture weitere wiederverwendbare Fixtures, z.B. zur Sitzungserzeugung Mocking, etc., verwenden.
Implementierung
Das Fixture stellt die Testumgebung bereit. Es ist als nested class innerhalb einer partiellen Klasse umzusetzen. Hier befinden sich auch die Setup- und Verify-Methoden zum Testaufbau und zur Prüfung der Testergebnisse. Die genaue Verwendung dieser Methoden ist in Testklassen für Unittests erstellen beschrieben.
Die Konstruktoren des Fixture werden oft auch aus der NUnit Infrastruktur aufgerufen (auch wenn der Test nur analyisiert und nicht durchgeführt wird) und sollten dementsprechend schnell sein (also z.B. keine Datenbankzugriffe tätigen).
BuecherAusleihenControllerTest.Fixture.cs
namespace Schleupen.AS.MT.BIB.Benutzerkonten; internal sealed partial class BuecherAusleihenControllerTest { private Fixture fixture; [SetUp] public void Setup() => fixture = new Fixture(); [TearDown] public void Dispose() => fixture?.Dispose(); private sealed class Fixture : IDisposable { public Mocks Mocks { get; } = new(); public TestData TestData { get; } = new(); public BuecherAusleihenController CreateTestObject() { return new BuecherAusleihenController( Mocks.BenutzerkontoRepositoryMock.Object, Mocks.BuchRepositoryMock.Object, Mocks.AusleiheRepositoryMock.Object, Mocks.DomainEventPublisherMock.Object); } public void Dispose() { } } private sealed class Mocks { public Mock<IReadOnlyBenutzerkontoRepository> BenutzerkontoRepositoryMock { get; } = new(); public Mock<IReadOnlyBuchRepository> BuchRepositoryMock { get; } = new(); public Mock<IAusleiheRepository> AusleiheRepositoryMock { get; } = new(); public Mock<IDomainEventPublisher> DomainEventPublisherMock { get; } = new(); } private sealed class TestData { } }
BuecherAusleihenControllerTest.cs
namespace Schleupen.AS.MT.BIB.Benutzerkonten; [TestFixture] internal sealed partial class BuecherAusleihenControllerTest { [Test] public void LeiheAusAsync_WhereBenutzerkontoDoesNotExist_ShouldThrowException() { BuecherAusleihenController testObject = fixture.CreateTestObject(); AusleihAuftrag testInput = new( fixture.TestData.ExternalIdOfBenutzer, fixture.TestData.Buecher.Select(buch => buch.Id), null, DateTimeOffset.Now); Assert.Throws<ValidationException>(() => testObject.LeiheAusAsync(testInput).GetAwaiter().GetResult()); } }
Die Fixture-Klasse selber rekombiniert dabei andere Fixtures:
- ein FachdatenFixture, das fachliche Objekte zur Verfügung stellt Persistenz-Fixture für Fachdaten erstellen
TransactionScopeFixture
SessionTokenFixture
(Vorsicht: hat eine Abhängigkeit zur CS 33.0-Infrastruktur und kann daher nur im AIT eingesetzt werden)
Stärken und Schwächen
Stärken
- Wiederverwendung von bereits vorhandenen Fixtures
- Es ist einfacher, voneinander unabhängige Tests zu schreiben
- Größere Übersichtlichkeit
Schwächen
- Erhöhter Implementierungsaufwand