Проектирование по контракту и разработка на основе тестирования


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

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

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

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

    Наша команда очень мала,
  • мы в основном используем Perl.
8 27

8 ответов:

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

Дизайн управляется контрактом. Конструкция, Управляемая Контрактом .

Разработка управляется тестом. Разработка На Основе Тестов .

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

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

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

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

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

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

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

  1. Начните с контракта,

  2. Затем

    A. напишите тесты и

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

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

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

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

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

Эта вторая часть не может быть заменена контрактами. Первая Часть может быть частично заменена контрактами, по крайней мере, для модульных тестов. TDD-тесты служат спецификациями поведения как для других разработчиков (модульные тесты), так и для экспертов предметной области (приемочные тесты). Контракты также определяют поведение, к другому разработчикам, экспертам по предметной области, а также компилятору и библиотеке времени выполнения. Но контракты имеют фиксированную степень детализации: у вас есть пред - и постусловия метода, инварианты объекта, контракты модулей и так далее. Может быть, варианты циклов и инварианты. Однако модульные тесты проверяют единицы поведения. Они могут быть меньше метода или состоять из нескольких методов. Это не то, что вы можете сделать с контрактами. А для "большой картины" вам еще нужны интеграционные тесты, функциональные тесты и приемосдаточные испытания. [2]} и есть еще одна важная часть TDD, которую DbC не охватывает: средний D. В TDD, тесты управляют процессом разработки: вы никогда не пишете ни одной строки кода реализации, если у вас нет провального теста, вы никогда не пишете ни одной строки кода тестирования, если все тесты не проходят, вы только пишете минимальное количество кода реализации, чтобы сделать тесты проходными, вы только пишете минимальное количество кода тестирования, чтобы произвести провальный тест.

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

Что-то вроде этого:

  1. написать приемочный тест для функции
  2. напишите модульный тест для устройства, реализующего часть этой функции
  3. используя сигнатуру метода, разработанную на Шаге 2, Напишите прототип метода
  4. добавьте постусловие
  5. добавить предварительное условие
  6. реализуем метод body
  7. Если приемо-сдаточный тест проходит, Гото 1, иначе Гото 2
Если вы хотите знать, что Бертран Мейер, изобретатель дизайна по контракту, думает об объединении TDD и DbC, есть хорошая статья его группы, называемая Contract-Driven Design = Test-Driven Development - Writing Test Cases. Основная предпосылка заключается в том, что контракты обеспечивают абстрактное представление всех возможных случаев, в то время как тестовые случаи только проверьте конкретные случаи. Таким образом, подходящий тестовый жгут может быть автоматически сгенерирован из контрактов.

Я бы добавил:

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

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

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

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

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

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

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

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

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

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

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

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

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

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