Помощь с подходом TDD к реальной проблеме: линкер - PullRequest
2 голосов
/ 18 ноября 2009

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

Linker.

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


Что ж, возможно, весь компоновщик является слишком большой проблемой для первого модульного теста. Я могу заранее представить себе грубую структуру. Что делает компоновщик:

  1. Представляет объектный файл как набор сегментов. Сегменты содержат код, данные, определения и ссылки на символы, отладочную информацию и т. Д.
  2. Создает справочный граф и решает, какие сегменты сохранить.
  3. Упаковывает оставшиеся сегменты в непрерывное адресное пространство в соответствии с некоторыми правилами.
  4. Перемещает ссылки.

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

Задача выглядит достаточно общей. Это происходит везде, где вам нужно поддерживать несколько форматов ввода, будь то обработка изображений, обработка документов, вы называете это. Возможно ли TDD? Кажется, что либо тест слишком прост, и я легко подхожу к зеленому, либо он немного сложнее, и мне нужно реализовать весь читатель формата объекта / изображения / документа, который содержит много кода. И нет никакого среднего уровня.

Ответы [ 5 ]

1 голос
/ 20 ноября 2009

Во-первых, взгляните на «Растущее объектно-ориентированное программное обеспечение, управляемое тестами» от Freeman & Pryce.

Теперь моя попытка ответить на сложный вопрос в несколько строк.

TDD требует, чтобы вы думали (т.е. проектировали), что вы собираетесь делать. Вы должны:

  1. Думай маленькими шагами. Очень маленькие шаги.
  2. Напишите короткий тест, чтобы доказать, что следующий небольшой фрагмент поведения работает.
  3. Запустите тест, чтобы показать, что он не прошел
  4. Сделайте самое простое, что нужно, чтобы пройти тест
  5. Рефакторинг безжалостно, чтобы убрать дублирование и улучшить структуру кода
  6. Запустите тест (ы) еще раз, чтобы убедиться, что все по-прежнему работает
  7. Вернуться к 1.

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

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

Тесты должны быть простыми. Легко «взломать» один тест на зеленый. Но после каждого «взлома» вы делаете рефакторинг. Если во время рефакторинга вы видите необходимость в новом классе или алгоритме, напишите тесты, чтобы вытеснить его интерфейс. Удостоверьтесь, что тесты когда-либо тестируют только одно поведение, сохраняя слабую связь ваших модулей (внедрение зависимостей, абстрактные базовые классы, интерфейсы, указатели функций и т. Д.), И используют подделки, заглушки и макеты, чтобы изолировать тестируемый код от остальной части вашего кода. система.

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

Это сложное изменение в мышлении, но очень весело и очень полезно. Честный.

0 голосов
/ 20 ноября 2009

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

Концентрируясь на своей точке 1, вы уже описали хороший набор единиц (функциональных возможностей), перечисляя виды вещей, которые могут появляться в сегментах, и намекая, что вам необходимо поддерживать несколько форматов. Почему бы не начать с простого случая, такого как, скажем, файл, содержащий только сегмент данных в двоичном формате вашей платформы разработки? Вы можете просто жестко закодировать файл в виде двоичного массива в своем тесте, а затем проверить, правильно ли он интерпретирует. Затем выберите другой простой случай и проверьте его. Продолжай.

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

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

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

0 голосов
/ 18 ноября 2009

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

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

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

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

0 голосов
/ 18 ноября 2009

TDD - это спецификация, а не тест.

Исходя из самой простой спецификации компоновщика, ваш тест TDD должен просто проверить, был ли создан исполняемый файл во время магии компоновщика, если вы кормите его объектным файлом.

Затем вы пишете компоновщик, который делает ваш тест успешным, например ::

  • проверить, является ли входной файл объектным файлом
  • если так, сгенерируйте "Hello World!" исполняемый файл (обратите внимание, что в вашей спецификации не указано, что разные объектные файлы будут создавать разные исполняемые файлы)

Затем вы уточняете свою спецификацию и свой TDD (это ваши четыре пули).

Пока вы можете написать спецификацию, вы можете писать тестовые случаи TDD.

0 голосов
/ 18 ноября 2009

Это все очень возможно.
Образец с макушки моей головы: NHAML .

Это ASP.NET ViewEngine, который преобразует простой текст в собственный код .NET.

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

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