SergeyTeplyakov / DesignPatternsBook

Паттерны проектирования на платформе .NET
32 stars 2 forks source link

Использование порождающих паттернов в юнит-тестах. Паттерн Test Fixture #260

Closed SergeyUsok closed 9 years ago

SergeyUsok commented 9 years ago

важны лишь в определенных случаях. В этом случае

случаях - случае. Мне кажется первый вариант можно заменить на "при определенных сценариях"

и для рассматриваемого случая будет выглядеть так

ОН будет выглядеть

Mock<IDependency в качестве свойства.

угловую скобку не закрыл

что сделает тесты значительно более читаемыми

наверное, "читабельными", поскольку, "читаемый" - это тот, который часто или много читают

В некоторых случаях можно воспользоваться

после "случаях" запятая

которые повысят читаемость тестов.

то же, что и выше - читабельность

Несколько вопросов по паттерну и коду: 1) Судя по коду строителя, ты позволяешь создать LogEntryReader с null аргументами, это нормально? 2) Откуда LogEntryReaderTestFactory? 3) Для меня странно название свойства Cut - это по паттерну так? 4) Ты писал о преимуществе тестовой фабрики перед использованием конструкторов в цене изменений в тестах в случае, если появится например еще один аргумент конструктора. Но в случае использования билдера эта цена снова может возрасти, так как придется менять опять все тесты. То есть я хочу сказать, что где-то в тексте возможно стоит сказать об этом случае и показать, что в билдере можно просто сделать третий аргумент с дефалтовым значением и таким образом показать, что это не одно и то же, что и использование конструкторов.

AlexanderSher commented 9 years ago

Пишу сюда же, чтобы не заводить отдельный тикет.

  1. Object Mother - это не просто фабричный метод, это достаточно специфичное сборище фабричных методов в одном классе. Т.е. вынесение логики инициализации в фабричный метод - это еще не Object Mother. Мне кажется, что если ты упоминаешь про новый для читателя паттерн, то надо или как-то хотя бы минимально его описать, или же обойтись уже известным читателю термином "фабричный метод".
  2. Вынесение инициализации в отдельные фабричные методы в общем случае не есть замена метода SetUp. Если у тебя в классе 50 тестов, и каждый из них содержит с десяток одинаковых шагов инициализации, каждый из которых возвращает нужный для теста объект, то разумно будет вынести это все в некий общий метод инициализации. Вот только туплов у нас в C# нормальных нет, а метод с 10 out-параметрами вызывает оторопь. Значит надо или заводить некий класс-контекст, или использовать поля самого класса с тестами (при условии конечно, что раннер пересоздаст нам инстанс этого класса для каждого вызова, как это делает, например, xUnit).
  3. Приведенный тобой пример Fixture вызывает желание выкинуть его и использовать Object Mother с дефолтными параметрами конструктора:
public static LogEntryReader CreateLogEntryReader(string content = null, ILogEntryParser parser = null)
{
    parser = parser ?? new SimpleLogEntryParser();
    content = content ?? string.Empty;
    return LogEntryReaderTestFactory.Create(content, parser);
}

Т.е. из примера не видно каких-то плюсов использования билдера. Я не знаю, можно ли что-то такое сделать именно с этим кодом. Билдер реально нужен, когда количество возможных состояний объекта условно бесконечно, и мы не можем все эти состояния представить в виде набора конструкторов (тот же FluentAssertions например). Или когда нужно изменить некое поведение объекта, например, чтобы сеттер вместо того, чтобы писать в объект, писал в переданную ему переменную, а геттер соответственно из этой переменной читал.

4.

Этот же подход позволяет спрятать в класс Fixture инициализацию моков, и выставить объект Mock<IDependency в качестве свойства.

Что такое IDependency? В главе оно вообще отсутствует.

SergeyTeplyakov commented 9 years ago

Ответ @SergeyUsok:

) Судя по коду строителя, ты позволяешь создать LogEntryReader с null аргументами, это нормально?

В книге обычно не приводится валидация аргументов. Ее практически нигде нет. Если она где-то есть, то ее нужно просто убрать.

2) Откуда LogEntryReaderTestFactory?

Переделаю.

3) Для меня странно название свойства Cut - это по паттерну так?

Это сокращение для Class Under Test. Переделаю.

4) Ты писал о преимуществе тестовой фабрики перед использованием конструкторов в цене изменений в тестах в случае, если появится например еще один аргумент конструктора. Но в случае использования билдера эта цена снова может возрасти, так как придется менять опять все тесты. То есть я хочу сказать, что где-то в тексте возможно стоит сказать об этом случае и показать, что в билдере можно просто сделать третий аргумент с дефалтовым значением и таким образом показать, что это не одно и то же, что и использование конструкторов.

Билдер в любом случае является прослойкой между создаваемым классом и клиентом. Это значит, что при изменении конструктора создаваемого класса поменяется билдер (что нормально) и, благодаря билдеру, поменяются лишь те тесты, которые были завязаны на уделнный параметр. Если же параметр добавляется в тестируемый класс, то билдер будет использовать параметры по умолчанию для этого аргумента, что позволит изменить лишь билдер, но не трогать все тесты.

Я не знаю, нужно ли на этом акцентировать внимание. Но, раз вопрос возник, то, скорее всего, нужно.

SergeyTeplyakov commented 9 years ago

@AlexanderSher

  1. По поводу ObjectMother: Да, ты прав. Все же ObjectMother - это фабрика аргументов тестируемого класса, а не фабрика самого тестируемого класса. Так что в этом случае используется именно фабричный метод. ИМХО, про Object Mother нужно упомянуть, здесь, все же, рассматриваются порождающие паттерны в тестах, но раздел так называть нельзя.
  2. Поправлю, чтобы четко отразить твое замечание.
  3. Я попробую сделать явный комментарий, что выгоды при трех параметрах будет не много, но будет выгоднее для тестирования более тяжеловесных объектов с более сложным процессом инициализации.
  4. Приведу явный пример.
SergeyTeplyakov commented 9 years ago

Ребят, гляньте на новый вариант плз.

Пока закрываю тикет. Открывайте новый или переоткрывайте этот в случае вопросов.