Проектирование по контракту и разработка через тестирование - PullRequest
28 голосов
/ 27 декабря 2008

Я работаю над улучшением процесса разработки нашей группы и обдумываю, как наилучшим образом реализовать Design By Contract с помощью Test-Driven Development. Кажется, что эти две техники имеют много общего, и мне было интересно, если бы кто-нибудь имел некоторое представление о следующих (связанных) вопросах:

  • Разве не противоречит принципу DRY иметь TDD и DbC, если вы не используете какой-то генератор кода для генерации модульных тестов на основе контрактов? В противном случае вы должны поддерживать контракт в двух местах (тест и сам контракт), или я что-то упустил?
  • В какой степени TDD делает DbC избыточным? Если я пишу тесты достаточно хорошо, разве они не эквивалентны написанию контракта? Получу ли я дополнительную выгоду только в том случае, если исполню контракт во время выполнения, а также в ходе испытаний?
  • Значительно ли проще / гибче использовать только TDD, а не TDD с DbC?

Основной вопрос этих вопросов - это более общий вопрос: Если мы уже правильно выполняем TDD, получим ли мы существенную выгоду для накладных расходов, если мы также будем использовать DbC?

Пара деталей, хотя я думаю, что вопрос в значительной степени не зависит от языка:

  • Наша команда очень мала, <10 программистов. </li>
  • В основном мы используем Perl.

Ответы [ 8 ]

35 голосов
/ 27 декабря 2008

Обратите внимание на различия.

Дизайн по договору. Контрактный Дизайн .

Разработка на основе теста. Test Driven Разработка .

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

Вы отказываетесь от дизайна, когда переходите к реализации? Считаете ли вы, что дизайн документа является нарушением СУХОГО? Поддерживаете ли вы договор и код отдельно?

Программное обеспечение является одной из реализаций контракта. Тесты это другое. Руководство пользователя третье. Руководство по эксплуатации является четвертым. Процедуры резервного копирования / восстановления базы данных являются частью реализации контракта.

Я не вижу никаких накладных расходов от Проектирования по контракту.

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

  • Если вы не занимаетесь проектированием, то написание контракта устранит проблемы, снизит стоимость и сложность.

Я не вижу потери гибкости.

  1. начать с контракта,

  2. тогда

    а. написать тесты и

    б. написать код

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

26 голосов
/ 27 декабря 2008

Я думаю, что есть дублирование между DbC и TDD, однако я не думаю, что есть дублирующаяся работа: введение DbC, вероятно, приведет к сокращению тестовых случаев.

Позвольте мне объяснить.

В TDD тесты на самом деле не являются тестами. Это поведенческие характеристики. Тем не менее, они являются и инструментами проектирования: сначала при написании теста вы используете внешний API тестируемого объекта - который вы еще не написали - так же, как и пользователь. Таким образом, вы разрабатываете API способом, который имеет смысл для пользователя, а не способом, который делает его более простым для реализации. Что-то вроде queue.full? вместо queue.num_entries == queue.size.

Эта вторая часть не может быть заменена Контрактами.

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

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

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

В заключение: используйте тесты для разработки «потока», «ощущения» API. Используйте контракты для разработки, ну, контракт API. Используйте тесты, чтобы обеспечить «ритм» для процесса разработки.

Примерно так:

  1. Написать приемочный тест для функции
  2. Напишите модульный тест для модуля, который реализует часть этой функции
  3. Используя подпись метода, которую вы разработали в шаге 2, напишите прототип метода
  4. Добавить постусловие
  5. Добавить предварительное условие
  6. Реализация метода тела
  7. Если приемочный тест пройден, переходите к 1, в противном случае переходите к 2

Если вы хотите узнать, что думает Бертран Мейер, изобретатель Design by Contract, о комбинировании TDD и DbC, есть замечательная статья его группы под названием Design-Driven Design = Test-Driven Development - Writing Тестовые случаи . Основная предпосылка заключается в том, что контракты обеспечивают абстрактное представление всех возможных случаев, тогда как тестовые случаи проверяют только конкретные случаи. Следовательно, из контрактов может быть автоматически сгенерирован подходящий тестовый комплект.

6 голосов
/ 27 декабря 2008

Я бы добавил:

API - это контракт для программистов, определение пользовательского интерфейса - это контракт с клиентами, протокол - это контракт для взаимодействия клиент-сервер. Получите их в первую очередь, тогда вы сможете воспользоваться параллельными путями разработки и не потеряться в сорняках. Да, периодически проверяйте, чтобы убедиться, что требования выполнены, но никогда не начинайте новый трек без контракта. И «контракт» - это сильное слово: после развертывания оно никогда не должно меняться. Вы должны включить управление версиями и самоанализ с самого начала, изменения в контракте реализуются только наборами расширений, номера версий меняются вместе с ними, а затем вы можете делать такие вещи, как постепенное снижение производительности при работе со смешанными или старыми установками.

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

Я немного подозрительно отношусь к дизайну TLA. Как и в случае с паттернами, рецепты, отвечающие модным словам, являются хорошим руководством, но, по моему опыту, такой вещи, как универсальный дизайн или процедура управления проектом, не существует. Если вы делаете все именно по Книге (tm), то, если это не договор DOD с процедурными требованиями DOD, вы, вероятно, столкнетесь с проблемами где-нибудь по пути. Прочитайте Книгу (ы), да, но будьте уверены, что поймете их, а затем примите во внимание и личную сторону вашей команды. Правила, которые применяются только Книгой, не будут применены единообразно - даже когда инструменты применяются, могут быть пропуски (например, svn комментарии оставлены пустыми или загадочно краткими). Процедуры, как правило, выполняются только в том случае, если цепочка инструментов не только обеспечивает их выполнение, но и упрощает отслеживание, чем любые возможные сокращения. Поверьте, когда наступают тяжелые времена, выявляются короткие пути, и вы можете не знать о тех, которые использовались в 3 часа ночи, пока не стало слишком поздно.

2 голосов
/ 13 марта 2009

Вы также можете использовать исполняемые приемочные тесты, написанные на доменном языке договора. Это может быть не фактический «контракт», а половина пути между юнит-тестами и контрактом.

Я бы рекомендовал использовать Ruby Cucumber. http://github.com/aslakhellesoy/cucumber

Но так как вы магазин Perl, то, возможно, вы можете использовать мою маленькую попытку p5-огурца. http://github.com/kesor/p5-cucumber

1 голос
/ 13 марта 2009

Microsoft выполнила работу по автоматической генерации модульных тестов на основе контрактных кодов и параметризованных модульных тестов. Например. В контракте говорится, что количество должно быть увеличено на единицу при добавлении элемента в коллекцию, а параметризованный модульный тест говорит, как добавить «n» элементов в коллекцию. Затем Пекс попытается создать модульный тест, который доказывает, что контракт расторгнут. Смотрите это видео для обзора.

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

0 голосов
/ 30 октября 2014

Мне показалось, что DbC очень удобен для быстрого запуска цикла red-green-refactor , потому что он помогает идентифицировать модульные тесты, с которых нужно начинать. С DbC я начинаю думать о предварительных условиях , которые объект TDD-ed должен обрабатывать, и каждое предварительное условие может представлять собой неудачный модульный тест для запуска цикла красно-зеленого-рефакторинга. В какой-то момент я переключаюсь, чтобы запустить цикл с неудачным модульным тестом для постусловия , а затем просто поддерживаю поток TDD. Я попробовал этот подход с новичками в TDD, и он действительно помогает запустить мышление TDD.

В целом, думайте о DbC как об эффективном способе определения ключевых поведенческих юнит-тестов. DbC помогает анализировать входные данные (предварительные условия) и выходные данные (постусловия), которые мы должны контролировать (входные данные) и наблюдать (выходные данные) для написания тестируемого программного обеспечения (аналогичная цель TDD).

0 голосов
/ 14 сентября 2011

Когда вы используете TDD для реализации нового метода, вам нужны некоторые данные: вам нужно знать утверждения для проверки в ваших тестах. Проектирование по контракту дает вам эти утверждения: они являются постусловиями и инвариантами метода.

0 голосов
/ 07 декабря 2009

У меня были некоторые размышления на эту тему некоторое время назад.

Возможно, вы захотите взглянуть на

http://gleichmann.wordpress.com/2007/12/09/test-driven-development-and-design-by-contract-friend-or-foe/

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...