TDD - снаружи внутрь против снаружи


53

В чем разница между созданием приложения Outside In и Inside Out с использованием TDD?

Это книги, которые я прочитал о TDD и модульном тестировании:
Разработка через тестирование: на примере Разработка через
тестирование: Практическое руководство: Практическое руководство
Реальные решения для разработки высококачественных фреймворков PHP и разработка приложений на основе
тестов в Microsoft.
Тестовые шаблоны NET xUnit: рефакторинг тестового кода
Искусство модульного тестирования: с примерами в растущем
объектно-ориентированном программном обеспечении .Net , руководствуясь тестами ---> Это было действительно трудно понять, поскольку JAVA не является моим основным языком :)

Почти все они объяснили основы TDD и модульное тестирование в целом, но с небольшим упоминанием различных способов создания приложения.

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

Однако в xUnit Test Patterns я натолкнулся на параграф, в котором обсуждается, как люди подходят к TDD. Есть 2 школы снаружи снаружи и внутри снаружи .

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


Два подхода описаны на сайте тестовых шаблонов XUnit: xunitpatterns.com/Philosophy%20Of%20Test%20Automation.html . Странно, что их нет в книге.
guillaume31

Ответы:


45

Inside-Out и Outside-In - довольно редкие термины, чаще я слышал / читал о классической школе и лондонской школе .

  • Inside-Out (Классическая школа, снизу вверх ): вы начинаете с уровня компонента / класса (внутри) и добавляете тесты к требованиям. По мере развития кода (благодаря рефакторингу) появляются новые соавторы, взаимодействия и другие компоненты. TDD полностью руководит дизайном.

  • Аутсайд-Ин (лондонская школа, « сверху вниз» или «TD-mockist», как назвал бы это Мартин Фаулер): вы знаете об взаимодействиях и соавторах заранее (особенно на высших уровнях) и начинаете там (верхний уровень), высмеивая необходимые зависимости. С каждым готовым компонентом вы переходите к ранее смоделированным соавторам и снова начинаете с TDD, создавая реальные реализации (которые, хотя и использовались, раньше не требовались благодаря абстракциям ). Обратите внимание, что внешний подход хорошо сочетается с принципом YAGNI .

Ни один из подходов не является единственным и единственным ; они оба имеют свое место в зависимости от того, что вы делаете. В крупных корпоративных решениях, где части дизайна исходят от архитекторов (или существуют заранее), можно начать с подхода «лондонского стиля». С другой стороны, когда вы сталкиваетесь с ситуацией, когда вы не уверены, как должен выглядеть ваш код (или как он должен вписываться в другие части вашей системы), может быть проще начать с какого-нибудь бюджетного компонента и позволить ему развиваться по мере появления новых тестов, рефакторингов и требований.

Что бы вы ни использовали, чаще всего это ситуативно.

Для дальнейшего чтения есть пост в группе Google с довольно интересным обсуждением того, как возникло это различие (и почему), и почему Лондон может быть не самым подходящим названием.


2
Интересно. Как вы пришли к выводу, что снаружи в TDD это "mockist" TDD? Я очень предпочитаю нестандартное мышление и дизайн и, следовательно, тестирование (см. Softwareonastring.com/2015/01/10/… ), однако статья Фаулера твердо ставит меня с Фаулером в лагерь классицистов. В то время как mockist всегда может использовать внешний подход, вы не можете перевернуть его и сказать, что внешний дизайн и тестирование - это TDD. Аутсайдер может быть и очень часто практикуется классиками TDD.
Марьян Венема

@jimmy_keen - С внешней стороны, в какой-то момент вы заменяете макеты в тестах более высокого уровня на позднее созданные реальные реализации? Или вы оставляете их как поддельные зависимости, а затем используете весь производственный код в качестве интеграционного теста?
thehowler

1
Я не согласен с тем, что Classic / Mockist и Inside-Out / Outside-In связаны между собой. Они ортогональны. Вы можете использовать Inside-Out / Outside-In с любым из них.
Даниэль Каплан

Согласитесь с Даниэлем. Вы сравниваете две разные таксономии. Хотя внешнее развитие часто ассоциируется с лондонской (mockist) школой, это не всегда так.
guillaume31

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

15

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

Кодирование наизнанку прекрасно, потому что у вас всегда есть что-то работающее Недостатком является то, что это не обязательно поможет вам добраться до совершенно другого места. Так сложнее наметить курс. Точно так же, написание кода снаружи in имеет недостаток, заключающийся в том, что он не обязательно имеет преимущество быстрой итеративной разработки и не обязательно рассматривает все возможности и шаблоны, которые могут возникнуть из-за глубины структуры кода.

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

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


8

Вы должны добавить Agile Принципы, Шаблоны и Практики в C # к этому списку. Я не знаю, почему он добавил "в C #" в конце. Книги вовсе не являются языком, и единственная причина, по которой он не получил 5 звезд на Амазонке, от людей, которые были разочарованы в C # -ness его примеров.

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

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

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


7

На мой взгляд, концепция внешнего развития действительно распространяется на 2 уровня. Джерард Месарош кратко описывает их как « дизайн снаружи-внутрь» и « кодирование снаружи-внутрь / изнутри ».

  • Первый уровень - это уровень организации и процесса. Под дизайном снаружи подразумевается нисходящий (водопад / тейлист) и восходящий. При внешнем подходе мы ориентируемся на точку зрения конечного пользователя. Мы начнем с тестов истории, тестов ATDD или BDD и перейдем к «внутренним» выводам технических тестов и кода. Таким образом, внешний дизайн - это то, что вы делаете в Agile-контексте. Дэн Норт отлично рассказывает о подходах BDD, сверху вниз, снизу вверх и снаружи.

  • Второй уровень является техническим и связан с аппликативными слоями. Внешнее кодирование в основном означает, начиная с пользовательского интерфейса и переходя внутрь на центральный уровень (обычно уровень бизнес / домен). Это в отличие от кодирования наизнанку, которое начинается с центрального уровня и кодируется внешними уровнями в последнюю очередь.

Таким образом, у вас может быть внешний дизайн с кодированием снаружи или изнутри.

Я не согласен с Месарошем в том, что когда он связывает внутреннее кодирование с интеграционным тестированием, утверждая, что в контексте внутреннего контекста «мы на самом деле не тестируем внешнее программное обеспечение изолированно от внутреннего программного обеспечения». Но я верю, что ничто не мешает вам сделать это. Вы можете идеально выбрать для тестирования ваших объектов внешнего слоя, имитируя объекты внутреннего слоя, даже если рабочий код для них уже существует. Вам просто нужно добавить интерфейсы и макеты поверх существующих конкретных объектов вместо того, чтобы писать интерфейсы, насмехаться над ними, а затем создавать реализации позже, как вы это сделали бы с внешним кодированием.

Другими словами, TDD в стиле mockist или classicist - это IMO, ортогональный подход к кодированию снаружи-внутрь / изнутри. Вы можете прекрасно использовать стиль mockist вместе с подходом наизнанку. Причиной этого является то, что стиль mockist / classicist связан с зависимостями кода, в то время как внешнее / внутреннее кодирование связано с аппликативными уровнями .

Еще одна важная вещь заключается в том, что зависимости существуют не только между слоями, они также существуют между объектами в одном слое. Например, вы можете начать с одного объекта на центральном бизнес-уровне (подход наизнанку) и использовать макеты, чтобы изолировать ваш объект от других объектов бизнес-уровня, с которыми он общается. Это часто случается с IoC - абстракции, от которых зависит ваш объект, часто объявляются на одном и том же уровне, но конкретные реализации находятся на другом уровне.

Роберт «Дядя Боб» Мартин в своем посте « Чистая архитектура » кратко упоминает о внутреннем кодировании и о том, как оно не обязательно конфликтует с несвязной архитектурой .

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.