Как вы делаете TDD в нетривиальном приложении?

Я прочитал несколько книг и веб-сайтов по теме TDD, и все они имеют большой смысл, особенно книгу Кента Бекка. Однако, когда я пытаюсь сам делать TDD, я вижу, что уставился на клавиатуру, задаваясь вопросом, с чего начать. Есть ли процесс, который вы используете? Каков ваш мыслительный процесс? Как вы идентифицируете свои первые тесты?

Большинство книг по этой теме прекрасно справляются с описанием того, что такое TDD, но не как практиковать TDD в нетривиальных приложениях реального мира. Как вы делаете TDD?

Ответы

Ответ 1

У меня была такая же проблема. Раньше я начинал большую разработку, запустив конструктор окон для создания пользовательского интерфейса для первой функции, которую я хотел реализовать. Поскольку пользовательский интерфейс является одним из самых трудных для тестирования этого способа работы, он не очень хорошо переводится в TDD.

Я нашел документы об атомных объектах на Presenter First очень полезными. Я все еще начинаю с представления действий пользователя, которые я хочу реализовать (если у вас есть возможности для запуска, которые отличные возможности для запуска), и используя модель MVP или MVC-ish, я начинаю с написания теста для ведущего первого экрана. Измотав представление до тех пор, пока работа ведущего, я не смогу начать работу так быстро. http://www.atomicobject.com/pages/Presenter+First здесь больше информации о работе по этому пути.

Если вы начинаете проект на незнакомом вам языке или фреймворке или имеете много неизвестных, вы можете начать делать всплеск первым. Я часто пишу модульные тесты для своих шипов, но только для запуска кода, который я пишу. Выполнение всплеска может дать вам некоторое представление о том, как начать свой реальный проект. Не забудьте выбросить свой всплеск, когда вы начнете свой реальный проект.

Ответ 2

Это проще, чем вы думаете, на самом деле. Вы просто используете TDD для каждого отдельного класса. Каждый общедоступный метод, который у вас есть в классе, должен быть проверен на все возможные результаты. Таким образом, "доказательства концепции", которые вы видите, также можно использовать в относительно большом приложении, которое содержит много сотен классов.

Еще одна стратегия TDD, которую вы можете использовать, - это имитация тестов на выполнение приложений, путем инкапсуляции основного поведения приложения. Например, я написал фреймворк (на С++, но это должно относиться к любому языку OO), который представляет собой приложение. Существуют абстрактные классы для инициализации, основной runloop и закрытия. Поэтому мой метод main() выглядит примерно так:

int main(int argc, char *argv[]) {
  int result = 0;

  myApp &mw = getApp(); // Singleton method to return main app instance
  if(mw.initialize(argc, argv) == kErrorNone) {
    result = mw.run();
  }

  mw.shutdown();
  return(result);
}

Преимущество этого в два раза. Прежде всего, все основные функциональные возможности приложения могут быть скомпилированы в статическую библиотеку, которая затем связана как с набором тестов, так и с этим файлом-заглушкой main.cpp. Во-вторых, это означает, что я могу моделировать целые "прогоны" основного приложения, создавая массивы для argc и argv [], а затем моделируя, что произойдет в main(). Мы используем этот процесс для тестирования множества функциональных возможностей реального мира, чтобы убедиться, что приложение генерирует именно то, что оно должно было делать, с учетом определенного реального мира исходных данных и аргументов командной строки.

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

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

Ответ 3

Я начинаю с размышлений о требованиях.

foreach UseCase

  • проанализировать UseCase
  • думать о будущих классах
  • записать тестовые примеры
  • написать тесты
  • тестирование и реализация классов (иногда добавление новых тестов, если я пропустил sth в точке 4).

Что это. Это довольно просто, но я думаю, что это требует много времени. Мне это нравится, и я придерживаюсь этого.:)

Если у меня больше времени, я пытаюсь смоделировать некоторые последовательные диаграммы в Enterprise Architect.

Ответ 4

Я согласен с тем, что особенно сложно загружать процесс.

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

Actor1 рассказывает Actor2, что мир в беде, Actor2 отдает пакет, Actor1 распаковывает пакет, и др.

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

Кроме того, я уверен, что последнее, что вы хотите сделать, это прочитать другую книгу, но ребята из MockObjects.com имеют книгу на ранних этапах проекта, в настоящее время под названием Растущее объектно-ориентированное программное обеспечение, руководствуясь тестами. Главы, которые в настоящее время рассматриваются, могут дать вам некоторое представление о том, как запустить TDD и продолжить его на протяжении всего времени.

Ответ 5

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

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

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

Ответ 6

Я не думаю, что вы действительно должны начать с TDD. Серьезно, где ваши спецификации? Согласны ли вы с общим/грубым общим дизайном вашей системы, который может быть подходящим для вашей заявки? Я знаю, что TDD и гибкие препятствия Big Design Up-Front, но это не значит, что вы не должны делать Design Up-Front сначала перед тем, как TDD поступить через реализацию этого дизайна.

Ответ 7

Иногда вы не знаете, как делать TDD, потому что ваш код не является "дружественным к тестированию" (легко проверяемый).

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

Недавно я наткнулся на блог сотрудником Google, в котором описывается, как вы можете создавать свои классы и методы, чтобы они были проще тест.

Вот один из его недавних переговоров, который я рекомендую.

Он настаивает на том, что вам нужно отделить бизнес-логику от кода создания объекта (т.е. избежать смешивания логики с "новым" оператором), используя шаблон Injection Dependency. Он также объясняет, как Закон Деметры важен для проверяемого кода. Он в основном сосредоточился на Java-коде (и Guice), но его принципы должны применяться на любом языке.

Ответ 8

Самый простой способ - начать с класса, у которого нет зависимостей, класса, который используется другими классами, но не использует другой класс. Затем вы должны подобрать тест, спросив себя: "Как я могу узнать, правильно ли реализован этот класс (этот метод)?".

Затем вы можете написать первый тест для опроса своего объекта, когда он не инициализирован, он может вернуть NULL или выбросить исключение. Затем вы можете инициализировать (возможно, только частично) свой объект, а тестовый тест возвращает что-то ценное. Затем вы можете добавить тест с другим значением инициализации - должны вести себя одинаково. В то время я обычно проверяю условие ошибки - например, пытается инициализировать объект с недопустимым значением.

Когда вы закончите с этим методом, перейдите к другому методу того же класса, пока не закончите со всем классом.

Затем вы можете выбрать другой класс - либо другой независимый класс, либо класс, который использует первый класс, который вы реализовали.

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

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

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


Если у вас уже есть свой дизайн - как вы указали в комментарии в ответе от Jon LimJap, тогда вы не делаете чистого TDD, так как TDD об использовании модульных тестов, чтобы ваш дизайн появился.

Тем не менее, не все магазины допускают строгую TDD, и у вас есть дизайн под рукой, поэтому пусть он использует его и делает TDD - хотя лучше сказать, что Test-First-Programming, но это не так, также как я начал TDD.