BDD — рабочий метод или TDD в модной обертке?


Разработка через тестирование



При unit-тестированиии кода рано или поздно встает вопрос тестовых данных. И если в одном случае достаточно просто несколько жестко зашитых переменных, то в других случаях необходимы сколько-нибудь большие и случайные данные. В управляемом мире нет проблем с генерацией пользовательских типов (взять тот же Autofixture), но мир C++ зачастую вызывает боль и страдание (поправьте меня, если это не так). Не так давно я познакомился с замечательной библиотекой boost::di и под ее влиянием у меня начала созревать идея библиотеки, которая позволила бы C++ программистам генерировать пользовательские типы данных, забитых случайными значаниями, и это не потребовало бы предварительного их описания. Получилось что-то вроде:
struct dummy_member{
float a;
int b;
};
struct dummy{
explicit dummy(dummy_member val, std::string c) : val_(val), c_(c) {}
private:
dummy_member val_;
std::string c_;
};
int main(int argc, char* argv){
auto d = datagen::random<dummy>();
return 0;
}→ Ссылка на код. Библиотека header-only,C++14. Всех интересующихся прошу под кат.


Git tag: Step12
Наступил завершающий этап нашего приключения в поисках чистой архитектуры. Мы создали модели предметной области, сериализаторы, сценарии и хранилище. Но пока отсутствует интерфейс, который склеивает все вместе: получает параметры вызова от пользователя, инициализирует сценарий с хранилищем, выполняет сценарий, который получает модели предметной области из хранилища, и преобразует их в стандартный формат. Этот слой может быть представлен с помощью множества интерфейсов и технологий. Например, с помощью интерфейса командной строки (CLI): получать параметры с помощью ключей командной строки и возвращать результат в виде текста на консоли. Но та же базовая система может быть использована и для web-страницы, которая получает параметры вызова из набора виджетов, выполняет описанные выше шаги, и разбирает возвращенные данные в формате JSON для отображения результата на той же странице.
Вне зависимости от выбранной технологии, для взаимодействия с пользователем, сбора входных данных и предоставления выходных результатов, нам необходимо взаимодействовать с недавно созданной чистой архитектурой. Поэтому сейчас мы создадим слой для вынесения наружу API для работы с HTTP. Реализовано это будет при помощи сервера, который предоставляет набор HTTP-адресов (конечных точек API), при обращении к которым возвращаются некоторые данные. Такой слой обычно называют REST-слой, потому что, как правило, семантика адресов схожа с рекомендациями REST.

Git tag: Step09
Наша реализация ответов и запросов, наконец, завершена. И теперь мы можем реализовать последнюю версию нашего сценария. Сценарий корректно возвращает объект ResponseSuccess, но до сих пор не проверяет корректность входящего запроса.
Давайте изменим тест в файле tests/use_cases/test_storageroom_list_use_case.py и добавим ещё 2 теста. Полученный набор тестов (после фикстуры domain_storagerooms) выглядит следующим образом:

Обычным подходом в .NET к тестированию приложений работающих с базой данных является внедрение зависимостей (Dependency Injection). Предлагается отделить код работающий с базой, от основной логики путем создания абстракции, которую в дальнейшем можно подменить в тестах. Это очень мощный и гибкий подход, который тем не менее имеет некоторые недостатки — увеличение сложности, разделение логики, взрывной рост количества типов. Подробнее в предыдущей статье Что-то не то с тестированием в .NET (Java и т.д.) или в Wiki/Dependency Injection.
Есть более простой подход, широко распространенный в мире динамических языков. Вместо создания абстракции, которую можно контролировать в тестах, этот подход предлагает контролировать саму базу. Тестовый фреймворк предоставляет чистую базу для каждого теста и вы можете создать в ней тестовый сценарий. Это проще и дает больше уверенности в тестах.

StorageRoom. Как было сказано ранее, модели в чистой архитектуре очень легкие, по крайней мере, легче, чем их ORM-аналоги в фреймворках.tests/domain/test_storageroom.py и поместим внутри него этот код:
Год назад мой друг Roberto Ciatti познакомил меня с концепцией, которую Роберт Мартин называет чистой архитектурой. Дядя Боб много говорит об этой концепции на конференциях и пишет о ней очень интересные статьи. «Чистая архитектура» представляет собой способ структурирования системы программного обеспечения, набор соглашений о различных слоях и ролях их участников, нечто большее, чем строгие правила.
Как он уже говорил в своей статье «Чистая архитектура» (перевод на хабре), идея самого подхода не нова, она строится на множестве концепций, которые продвигались многими разработчиками программного обеспечения в течение последних 3-х десяти лет.
Для начала я приведу небольшой тестовый проект из трёх классов, проанализирую его покрытие с помощью гема SimpleCov, а напоследок немного поразмышляю о том, как анализ покрытия может приносить пользу проекту, и какие есть недостатки у Coverage в Ruby.
В качестве проекта для тестирования взята небольшая история о мальчике, который может спрашивать разрешения погулять у матери и у отца.
# Мама очень заботится о своём сыне, и не разрешает ему гулять,
# если он не надел шарф. А ещё она заботится о его успеваемости, поэтому если
# сын не сделал домашнюю работу, гулять ему она тоже не разрешит.
class Mother
def permit_walk?(child)
child.scarf_put_on && child.homework_done
end
end
В этой серии статей мы строим программное обеспечение марсохода в соответствии со следующими спецификациями. Это позволит применить нам на практике следующие подходы:
Марсоход, Введение
Марсоход, Инициализация
Марсоход, Посадка
Марсоход, Координаты посадки
В предыдущих частях мы создали пакет навигации, а в нем LandRover класс, который валидирует входные параметры для нашего первого способа использования:
Марсоход должен будет сначала приземлиться в заданном положении. Положение состоит из координат (XиY, являющихся целыми числами) и ориентации (строковое значениеnorth,east,westилиsouth).
Сегодня мы будем рефакторить LandRover:
В этой серии статей мы строим программное обеспечение марсохода в соответствии со следующими спецификациями. Это позволит применить нам на практике следующие подходы:
Марсоход, Введение
Марсоход, Инициализация
Марсоход, Посадка
Марсоход, Координаты посадки
Ранее мы создали пакет навигации, теперь можно приступать к разработке первого варианта использования:
Марсоход должен будет сначала приземлиться в заданном положении. Положение состоит из координат (XиY, являющихся целыми числами) и ориентации (строковое значениеnorth,east,westилиsouth).

TDD не работает.
Правда? Странно. У меня всегда работал хорошо.
А вот новое исследование говорит об обратном.
Новое исследование?
Да, глубокое исследование, повторившее шаги другого исследования, проведенного несколько лет назад. Оба показали, что TDD не работает. Новое исследование проходило в нескольких местах, использовало слепой анализ. Выглядит убедительно.
Авторы считают его убедительным?
Авторы рекомендуют проводить новые исследования. Но они скорее всего просто скромничают. Результаты довольно убедительные.
Какие результаты?



