Вопрос

Я начал использовать Autofixture http://autofixture.codeplex.com/ Поскольку мои тесты модуля были раздуты с большим количеством настроек данных. Я проводил больше времени на расстановку данных, чем писать мою единицу теста. Вот пример того, как выглядит мой исходный тест на единицу (пример, взятый из образец грузового приложения из DDD Blue Book)

[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();
}

Вот как я пытался ревертировать его с Autofixture

[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)));
}

Я хотел бы знать, есть ли лучший способ ревертировать его. Хотел бы сделать это короче и легче, чем это.

Это было полезно?

Решение

Ваша начальная попытка выглядит хорошо, но есть как минимум пару вещей, которые вы можете немного упростить.

Прежде всего, вы должны уметь уменьшить это:

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

к этому:

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

Так как вы не используете эти другие переменные. Однако это по существу заблокирует любое создание CarrierMovement, чтобы использовать те же четырех значений. Хотя каждый созданный CarrierMovement будет отдельный экземпляр, все они будут поделиться такими же четырьмя ценностями, и мне интересно, если это было то, что вы имели в виду?

В той же вене, что и выше, а не

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

ты можешь написать

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

Так как вы не используете carrierM Переменная. Тип вывоза будет выяснить, что вы регистрируете график из-за возвращаемого типа ФУНК.

Однако, предполагая, что конструктор расписания выглядит так:

public Schedule(IEnumerable<CarrierMovement> carrierMovements)

Вы могли бы вместо этого только что зарегистрировали carrierMovements так:

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

что приведет к тому, что автозагрузка автоматически разрешает график. Этот подход более удобны, потому что он позволяет добавлять параметр на конструктор расписания в будущем, не нарушая тест (до тех пор, пока Autofixture может разрешить тип параметра).

Тем не менее, мы можем сделать лучше, чем в этом случае, потому что мы на самом деле не используем carrierMovements переменная для чего-либо еще, чем регистрация. Что нам действительно нужно сделать, это просто чтобы сообщить Autofixture, как создавать экземпляры IEnumerable<CarrierMovement>. Отказ Если вам не волнует номер 50 (вы не должны), мы даже можем использовать синтаксис группы методов, как это:

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

Обратите внимание на отсутствие метода взыскания парунгеров: мы регистрируем функцию, и поскольку CreateMany<T> Метод возвращает IEnumerable<T> Тип вывоза заботится о остальных.

Тем не менее, это все детали. На более высоком уровне вы можете не захотеть не регистрировать CarrierMovement вообще. Предполагая этот конструктор:

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

Автофиксировка должна быть в состоянии понять это самостоятельно.

Он создаст новый экземпляр местонахождения для каждого отделения и прибывательностей, но это не отличается от того, что вы вручную сделали в оригинальном тесте.

Когда дело доходит до времени, по умолчанию Autofixture использует DateTime.Now, что, по крайней мере, гарантирует, что время прибытия никогда не будет до времени отправления. Тем не менее, они очень вероятно, будут идентичны, но вы всегда можете зарегистрировать функцию автоматической наращивания, если это проблема.

Учитывая эти соображения, вот альтернатива:

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();
}

Решить проблему с IList<CarrierMovement> Вам нужно будет зарегистрировать это. Вот один из способов сделать это:

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

Однако, поскольку вы спрашиваете, я подразумеваю, что конструктор графика выглядит так:

public Schedule(IList<CarrierMovement> carrierMovements)

и я действительно думаю, что вы должны пересмотреть изменение этого API, чтобы взять IEnumerable<Carriemovement>. Отказ С точки зрения дизайна API, поставляя коллекцию через любой элемент (включая конструктор), подразумевает, что элемент разрешен для изменения коллекции (например, путем добавления его добавления, удаления и очистки). Это вряд ли поведение, вы ожидаете от конструктора, поэтому не позволяйте этому.

Autofixture автоматически генерирует новые значения для всех Location Объекты в моем приведенном выше примере, но из-за скорости процессора, последующие экземпляры DateTime, вероятно, будут идентичными.

Если вы хотите увеличить данные DatiMes, вы можете написать небольшой класс, который увеличивает возвращенные даты времени каждый раз, когда он вызывает. Я оставлю реализацию этого класса для заинтересованного читателя, но вы могли бы зарегистрировать это так:

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

Предполагая, что эта API (еще раз обратите внимание на синтаксис группы методов выше):

public class DateTimeGenerator
{
    public DateTime Next();
}
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top