Алгоритм записывается на одном из языков программирования на этапе отладки и тестирования

[при обработке этой директивы произошла ошибка]


Значение терминов

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

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

Предпосылки для эффективной отладки

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

  • Разберитесь в дизайне и алгоритме — Если вы работаете над модулем и не понимаете его конструкции или алгоритмов. То отладка будет очень сложной. Если вы не понимаете дизайн, то вы не можете протестировать модуль, потому что вы не знаете, что он должен делать. Если вы не понимаете алгоритмов, то вам будет очень трудно найти ошибки, которые обнаруживаются при тестировании. Вторая причина важности понимания алгоритмов заключается в том. Что вам может понадобиться это понимание для построения хороших тестовых случаев. Это особенно верно для алгоритмов сложных структур данных.

  • Проверка правильности — Существует несколько методов проверки правильности реализации перед выполнением.
  • Доказательства правильности — Одной из полезных проверок кода является проверка кода с использованием логических методов доказательства корректности. Например, если вы знаете предварительные условия, инварианты, конечные условия и постусловия для цикла. То есть несколько простых проверок. Которые вы можете сделать. Означает ли предварительное условие вместе с любым кодом ввода цикла, что инвариант изначально истинен? Сохраняет ли тело цикла инвариант? Делает ли выполнение тела цикла прогресс в направлении завершения цикла?

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

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

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

  • Экспертные оценки — Одноранговая проверка включает в себя одноранговую проверку вашего кода на наличие ошибок. Чтобы быть эффективным, одноранговый узел должен либо уже быть знаком с алгоритмом. Либо должен быть заранее задан алгоритм и код. Когда рецензент встречается с автором кода, автор кода должен представить код с объяснениями того. Как он правильно реализует алгоритм. Если рецензент не понимает или не согласен с частью реализации, они обсуждают эту часть, пока оба не придут к согласию о том. Является ли это ошибкой. Роль рецензента заключается только в помощи в обнаружении ошибок.

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

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

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

Требования к отладке

Для эффективной отладки кода вам нужны две возможности.

Во-первых, нужно уметь эффективно обращаться к услугам, предоставляемым модулем. Затем вы должны иметь возможность получать информацию о результатах вызовов, изменениях во внутреннем состоянии модуля. Условиях ошибки и о том. Что модуль делал. Когда произошла ошибка.

Управление модулем

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

  • Проводные драйверы — Это основной программный модуль, содержащий фиксированную последовательность вызовов служб. Предоставляемых тестируемым модулем.

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

  • Интерпретаторы команд — Интерпретатор команд управляет тестируемым модулем. Считывая входные данные и интерпретируя их как команды для выполнения вызовов служб модуля.

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

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

Получение информации о модуле

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

Это приводит к потребности в трех видах информации для отладки.

  • Состояние модуля — Модули структуры данных обычно имеют службы для вставки и удаления данных. Эти службы почти никогда не генерируют выходные данные самостоятельно и часто не возвращают никакой информации через параметры. Поэтому для того. Чтобы протестировать или отладить модуль. Программист должен добавить код. Предоставляющий информацию об изменениях во внутреннем состоянии модуля. Обычно программист добавляет процедуры. Которые могут отображать содержимое данных модуля.

    Эти процедуры становятся доступными для модуля драйвера. Но обычно удаляются или становятся закрытыми после завершения тестирования. Для отладки полезно иметь процедуры. Которые показывают внутреннюю структуру. А также содержимое.

  • Ошибки модуля — Когда модуль имеет сложное внутреннее состояние. С неправильным кодом обычно возможно возникновение недопустимых состояний. Кроме того, возможно. Что частные подпрограммы вызываются неправильно. Обе эти ситуации являются ошибками модуля. Когда это практически возможно. Код может быть добавлен в модуль для обнаружения этих ошибок.

  • Состояние выполнения — Чтобы определить причину ошибок модуля. Необходимо знать. Какие службы и частные подпрограммы были вызваны при возникновении ошибки. Это состояние выполнения модуля. Одним из распространенных методов определения состояния выполнения является добавление отладочных операторов печати. Указывающих на вход и выход из сегментов кода.

Принципы отладки

  • Немедленно сообщайте об условиях ошибки — Много времени отладки тратится на обнуление причины ошибок. Чем раньше обнаружена ошибка. Тем легче найти ее причину. Если неправильное состояние модуля обнаруживается сразу же. Как только оно возникает. То причину часто можно определить с минимальными усилиями.

    Если он не обнаруживается до тех пор. Пока симптомы не появятся в клиентском интерфейсе. То может быть трудно сузить список возможных причин.

  • Максимизация полезной информации и легкость интерпретации — Очевидно, что максимизация полезной информации желательна. И что она должна быть легко интерпретируемой. Простота интерпретации важна в структурах данных. Некоторые ошибки модуля не могут быть легко обнаружены путем добавления проверок кода. Поскольку они зависят от всей структуры. Таким образом, важно иметь возможность отображать структуру в форме, которую можно легко сканировать на правильность.

  • Сведите к минимуму бесполезную и отвлекающую информацию — слишком много информации может быть таким же препятствием. Как и слишком мало. Если вам придется работать с распечаткой, которая показывает вход и выход из каждой процедуры в модуле. То вам будет очень трудно найти первое место. Где что-то пошло не так. В идеале отчеты о состоянии выполнения модуля должны выдаваться только при возникновении ошибки. Как правило. Отладочная информация. Которая говорит
  • Избегайте сложного одноразового кода тестирования

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

Средства отладки

Вспомогательные средства. Встроенные в язык программирования
  • Операторы Assert — Некоторые компиляторы Pascal и все компиляторы C, соответствующие стандарту ANSI, имеют процедуры assert. Процедура assert имеет один параметр. Который является логическим выражением. Когда выполняется вызов assert. Выражение вычисляется. Если он принимает значение true. То ничего не происходит. Если он принимает значение false. То программа завершается с сообщением об ошибке. Процедура assert может использоваться для обнаружения и сообщения об ошибках.
  • Трассировка — Многие компиляторы Pascal генерируют код. Который приводит к трассировке всякий раз. Когда возникает ошибка времени выполнения. Трассировка-это отчет о последовательности подпрограмм. Которые в данный момент активны. Иногда обратная трассировка также указывает номера строк в активных подпрограммах. Если таковая имеется, то обратная трассировка показывает, где произошла ошибка времени выполнения. Но программист должен определить. Где кроется ее причина.
  • Отладчики общего назначения — Многие компьютерные системы или компиляторы поставляются с отладочными программами. Например, большинство операционных систем UNIX имеют отладчики общего назначения. Такие как sdb и dbx. Программы отладки предоставляют возможности для пошагового выполнения программы и запуска программы с точками останова. Заданными пользователем. Когда линия с точкой останова собирается быть выполнена. Программа прерывается. Чтобы пользователь мог изучить или изменить данные программы. Программы отладки также могут обеспечить обратные трассировки в случае ошибок во время выполнения. Отладчики часто трудно научиться эффективно использовать. Если они являются единственным инструментом, используемым для отладки, то, скорее всего, они не сэкономят много времени. Например, отладка модуля структуры данных с помощью отладчика, но без хорошего тестового драйвера, скорее всего. Приведет к тому. Что вы потратите много времени на получение фрагментарной информации об ошибках.

Методы отладки

Инкрементное тестирование

В хорошем дизайне для сложного модуля код разбивается на множество подпрограмм. Большинство из которых имеют длину не более 10-15 строк. Для модуля, разработанного таким образом. Инкрементное тестирование дает значительные преимущества. Для инкрементного тестирования подпрограммы классифицируются по уровням, причем самыми низкоуровневыми являются те. Которые не вызывают другие подпрограммы. Если подпрограмма А вызывает подпрограмму В. То А является подпрограммой более высокого уровня. Чем В. Стратегия инкрементного тестирования заключается в том. Чтобы тестировать подпрограммы по отдельности. Работая от самого низкого уровня к более высокому. Чтобы выполнить тестирование на более низких уровнях. Тест-драйвер должен либо иметь возможность напрямую вызывать низкоуровневые подпрограммы. Либо программист должен иметь возможность предоставить несколько тестовых входных вариантов. Каждый из которых включает только небольшое количество низкоуровневых подпрограмм. Разработка этих тестовых случаев требует глубокого понимания алгоритмов модуля, а также хорошего воображения. Сила инкрементного тестирования заключается в том. Что в любой момент процесса существует лишь небольшое количество мест. Где могут возникнуть ошибки. Это автоматически делает отладочную информацию более значимой и приводит к более быстрое определение причины ошибки. Вторая причина инкрементного тестирования заключается в том. Что оно значительно снижает вероятность того. Что придется иметь дело с двумя или более ошибками одновременно. Множественные ошибки часто приводят к появлению запутанных указаний на ошибки.

Проверка на вменяемость

Низкоуровневый код в сложной структуре данных часто пишется с предположением. Что код более высокого уровня правильно реализует нужный алгоритм. Например, низкоуровневый код может быть написан в предположении. Что некоторая переменная или параметр не могут быть НУЛЕВЫМИ. Даже если это предположение оправдано алгоритмом, все равно может быть хорошей идеей провести тест, чтобы проверить. Выполняется ли условие. Потому что код более высокого уровня может быть реализован неправильно. Такая проверка называется проверкой на вменяемость. Если доступна процедура assert. То ее можно использовать для проверок. Преимущество проверок на вменяемость состоит в том. Что они позволяют выявить ошибки на ранней стадии.

Логические константы для включения или выключения отладочного кода

Если отладочный код добавляется в модуль. То часто бывает выгодно заключить его в оператор if. Который управляется булевой константой. Добавленной в модуль. Таким образом. Отладочный код может быть легко отключен. Но при необходимости легко доступен позже. Для разных этапов тестирования следует использовать разные константы, чтобы свести к минимуму бесполезную информацию.

Переменные ошибок для управления поведением программы после ошибок

Когда отладочные операторы печати добавляются в код. Существует возможность огромного взрыва бесполезной информации. Проблема в том. Что оператор print сам по себе будет выполняться независимо от наличия ошибки. Таким образом, если ошибка не появляется до тех пор. Пока не будет сделано большое количество вызовов подпрограмм. То большинство сообщений просто говорят вам. Что пока все в порядке. Эта проблема значительно усиливается. Если добавленный код отображает внутреннюю структуру структуры данных. Предполагая, что модуль имеет проверку на вменяемость для обнаружения ошибок. Ошибка В модуль можно добавить булеву переменную. Он должен быть инициализирован в false. Что указывает на отсутствие ошибки. Для большинства структур данных существует операция Create для инициализации. Переменная error может быть инициализирована одновременно. Вместо выхода проверки на вменяемость изменяются таким образом, что они устанавливают переменной error значение true. Затем отладочный код может быть заключен в операторы if, так что информация печатается только при обнаружении ошибок. Одним из возможных применений этого метода является получение информации обратной трассировки. Когда она недоступна иным способом.

Методы обратной трассировки

Чтобы получить обратную трассировку. Используйте логическое значение ошибки. Заданное проверками здравомыслия. В различных местах модуля добавляется отладочный код, управляемый переменной error, которая выводит текущую позицию. Обычно более экономично сначала запустить код с завершающей проверкой вменяемости. Затем вам нужно только добавить контролируемый отладочный код в тех местах. Где вызывается подпрограмма. Содержащая проверку вменяемости.

Исправление Ошибок Кода

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

Предположим. Что вы запускаете какой-то код и получаете ошибку сегментации. После некоторой проверки вы определяете. Что НУЛЕВОЙ указатель был передан в процедуру. Которая не проверяла NULL. Но все равно пыталась ссылаться через указатель. Следует ли добавить проверку нулевого указателя к процедуре. Заключая все тело процедуры в оператор if? На этот вопрос нельзя ответить без понимания конструкции и алгоритма. Может быть, если алгоритм правильно реализован, то указатель не может быть нулевым, поэтому процедура не выполняет проверку. Если это так. То добавление оператора if не устраняет причину проблемы. Вместо этого он усугубляет ситуацию. Скрывая симптомы. Проблема наверняка появится где-то еще. Но теперь симптомы будут еще дальше удалены от причины. Код, такой как проверка нулевого указателя. Следует добавлять только в том случае. Если вы уверены. Что он должен быть частью алгоритма. Если вы добавляете проверку нулевого указателя. Которая не требуется алгоритмом. То он должен сообщить об ошибке. Другими словами. Это должна быть проверка на вменяемость. [при обработке этой директивы произошла ошибка]