Frage

Ich begann AutoFixture verwenden http://autofixture.codeplex.com/ als meine Unit-Tests aufgebläht war mit vielen Daten-Setup. Ich war die Daten verbringen mehr Zeit auf seting als meine Unit-Test zu schreiben. Hier ist ein Beispiel dafür, wie meine erste Einheit Test aussieht (Beispiel aus der Fracht Anwendung Probe von DDD blau Buch entnommen)

[Test]
public void should_create_instance_with_correct_ctor_parameters()
{
    var carrierMovements = new List<CarrierMovement>();

    var deparureUnLocode1 = new UnLocode("AB44D");
    var departureLocation1 = new Location(deparureUnLocode1, "HAMBOURG");
    var arrivalUnLocode1 = new UnLocode("XX44D");
    var arrivalLocation1 = new Location(arrivalUnLocode1, "TUNIS");
    var departureDate1 = new DateTime(2010, 3, 15);
    var arrivalDate1 = new DateTime(2010, 5, 12);

    var carrierMovement1 = new CarrierMovement(departureLocation1, arrivalLocation1, departureDate1, arrivalDate1);

    var deparureUnLocode2 = new UnLocode("CXRET");
    var departureLocation2 = new Location(deparureUnLocode2, "GDANSK");
    var arrivalUnLocode2 = new UnLocode("ZEZD4");
    var arrivalLocation2 = new Location(arrivalUnLocode2, "LE HAVRE");
    var departureDate2 = new DateTime(2010, 3, 18);
    var arrivalDate2 = new DateTime(2010, 3, 31);

    var carrierMovement2 = new CarrierMovement(departureLocation2, arrivalLocation2, departureDate2, arrivalDate2);

    carrierMovements.Add(carrierMovement1);
    carrierMovements.Add(carrierMovement2);

    new Schedule(carrierMovements).ShouldNotBeNull();
}

Hier ist, wie ich versuchte, es mit AutoFixture Refactoring

[Test]
public void should_create_instance_with_correct_ctor_parameters_AutoFixture()
{
    var fixture = new Fixture();

    fixture.Register(() => new UnLocode(UnLocodeString()));

    var departureLoc = fixture.CreateAnonymous<Location>();
    var arrivalLoc = fixture.CreateAnonymous<Location>();
    var departureDateTime = fixture.CreateAnonymous<DateTime>();
    var arrivalDateTime = fixture.CreateAnonymous<DateTime>();

    fixture.Register<Location, Location, DateTime, DateTime, CarrierMovement>(
        (departure, arrival, departureTime, arrivalTime) => new CarrierMovement(departureLoc, arrivalLoc, departureDateTime, arrivalDateTime));

    var carrierMovements = fixture.CreateMany<CarrierMovement>(50).ToList();

    fixture.Register<List<CarrierMovement>, Schedule>((carrierM) => new Schedule(carrierMovements));

    var schedule = fixture.CreateAnonymous<Schedule>();

    schedule.ShouldNotBeNull();
}

private static string UnLocodeString()
{
    var stringBuilder = new StringBuilder();

    for (int i = 0; i < 5; i++)
        stringBuilder.Append(GetRandomUpperCaseCharacter(i));

    return stringBuilder.ToString();
}

private static char GetRandomUpperCaseCharacter(int seed)
{
    return ((char)((short)'A' + new Random(seed).Next(26)));
}

Ich möchte wissen, ob es besser ist, wie es Refactoring. Möchte es kürzer und leichter als das tun.

War es hilfreich?

Lösung

Ihr erster Versuch, sieht gut aus, aber es gibt zumindest ein paar Dinge, die Sie ein wenig vereinfachen können.

Zunächst einmal sollten Sie in der Lage sein, diese zu reduzieren:

fixture.Register<Location, Location, DateTime, DateTime, CarrierMovement>(
    (departure, arrival, departureTime, arrivalTime) =>
        new CarrierMovement(departureLoc, arrivalLoc, departureDateTime, arrivalDateTime));

folgt aus:

fixture.Register<Location, Location, DateTime, DateTime, CarrierMovement>(
    () => new CarrierMovement(departureLoc, arrivalLoc, departureDateTime, arrivalDateTime));

, da Sie nicht die anderen Variablen. Allerdings sperrt diese im Wesentlichen jede Schaffung von CarrierMovement die gleichen vier Werte zu verwenden. Obwohl jeder erstellt CarrierMovement eine separate Instanz sein wird, wird sie alle teilen die gleichen vier Werte, und ich frage mich, ob das war, was du gemeint?

In der gleichen Ader wie oben, anstelle von

fixture.Register<List<CarrierMovement>, Schedule>((carrierM) =>
    new Schedule(carrierMovements));

Sie schreiben

fixture.Register(() => new Schedule(carrierMovements));

, da Sie nicht die carrierM Variable verwenden. Typ Inferenz wird herausfinden, dass Sie wegen der Rückgabetyp der Func einen Zeitplan registrieren.

Wenn man jedoch annimmt, dass der Zeitplan Konstruktor sieht wie folgt aus:

public Schedule(IEnumerable<CarrierMovement> carrierMovements)

Sie stattdessen nur die carrierMovements wie diese registriert haben könnte:

fixture.Register<IEnumerable<CarrierMovement>>(carrierMovements);

, die AutoFixture würde dazu führen, dass automatisch Zeitplan richtig zu lösen. Dieser Ansatz ist besser wartbar, weil es Ihnen erlaubt, ohne zu brechen den Test (solange AutoFixture den Parametertyp auflösen kann) einen Parameter in den Schedule Konstruktor in der Zukunft hinzuzufügen.

Allerdings können wir es besser machen als in diesem Fall, weil wir nicht wirklich für alles, was den carrierMovements Variable anders als Anmeldung. Was wir wirklich tun müssen, ist nur AutoFixture zu sagen, wie Instanzen von IEnumerable<CarrierMovement> zu erstellen. Wenn Sie nicht über die Zahl 50 (sollte man nicht) ist es egal, können wir auch die Verfahrensgruppe Syntax wie folgt verwendet werden:

fixture.Register(fixture.CreateMany<CarrierMovement>);

Beachten Sie die fehlende Methodenaufruf Klammern. Wir eine Func sind registriert, und da die CreateMany<T> Methode gibt IEnumerable<T> Typ Inferencing kümmert sich um den Rest

Doch das sind alles Details. Auf einer höheren Ebene, möchten Sie vielleicht nicht CarrierMovement gar Registrierung betrachten. Unter der Annahme, diesen Konstruktor:

public CarrierMovement(Location departureLocation,
    Location arrivalLocation,
    DateTime departureTime,
    DateTime arrivalTime)

autofixture sollte es in der Lage sein, sich selbst zu verstehen.

Es wird eine neue Location-Instanz für jeden departureLocation und arrivalLocation schaffen, aber das ist nicht anders als das, was Sie bei der ursprünglichen Prüfung manuell getan haben.

Wenn es um die Zeiten, die standardmäßig AutoFixture Anwendungen DateTime.Now, die zumindest sichergestellt, dass die Ankunftszeit wird nie vor der Abfahrtszeit sein. Sie sind jedoch sehr wahrscheinlich identisch sein, aber man konnte immer eine automatisch inkrementierende Funktion registrieren, wenn das ein Problem ist.

Diese Überlegungen gegeben, hier ist eine Alternative:

public void should_create_instance_with_correct_ctor_parameters_AutoFixture()
{
    var fixture = new Fixture();

    fixture.Register(() => new UnLocode(UnLocodeString()));

    fixture.Register(fixture.CreateMany<CarrierMovement>);

    var schedule = fixture.CreateAnonymous<Schedule>();

    schedule.ShouldNotBeNull();
}

Um das Problem mit IList<CarrierMovement> lösen Sie sie registrieren müssen. Hier ist eine Möglichkeit, es zu tun:

fixture.Register<IList<CarrierMovement>>(() =>
    fixture.CreateMany<CarrierMovement>().ToList());

Da Sie fragen, ich implizieren, dass die Schedule Konstruktor sieht wie folgt aus:

public Schedule(IList<CarrierMovement> carrierMovements)

, und ich glaube wirklich, Sie überdenken sollte, dass die API Ändern eines IEnumerable<Carriemovement> zu nehmen. Aus gestalterischer Sicht API, eine Sammlung durch irgendein Mitglied liefert (einschließlich eines Konstruktors) impliziert, daß das Element um die Sammlung zu modifizieren erlaubt ist (zum Beispiel durch seine Hinzufügen, Entfernen und Löschen Methoden aufrufen). Das ist kaum Verhalten, das Sie von einem Konstruktor erwarten würden, so tut es nicht zulassen.

AutoFixture automatisch neue Werte generieren für alle Location in meinem obigen Beispiel Objekte, aber aufgrund der Geschwindigkeit der CPU, sind nachfolgende Instanzen von Datetime wahrscheinlich identisch sein.

Wenn Sie wollen Datetime erhöhen, können Sie eine kleine Klasse schreiben, dass erhöht die Datetime jedes Mal kehrte er aufgerufen wird. Ich werde die Implementierung dieser Klasse des interessierten Leser überlassen, aber man kann es dann registrieren, etwa so:

var dtg = new DateTimeGenerator();
fixture.Register(dtg.Next);

vorausgesetzt diese API (Anmerkung erneut die Methode Gruppe Syntax oben):

public class DateTimeGenerator
{
    public DateTime Next();
}
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top