Автор Анна Евкова
Преподаватель который помогает студентам и школьникам в учёбе.

Отладка и тестирование программ: основные подходы и ограничения (Основные принципы отладки и тестирования)

Содержание:

ВВЕДЕНИЕ

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

Отладка и тестирование являются одинаково важными инструментами в разработке и привлекают внимание исследователей в области компьютерных наук в последние годы. Несмотря на наличие различных инструментов для обеспечения качества программного обеспечения посредством тестирования, для большого количества проектов нет общего подтверждения того, в достаточной ли степени они протестированы. Это ключевой момент, поскольку влияние неполного тестирования может заключаться в значительном количестве необработанных сбоев, что приводит к низкому качеству программного обеспечения, более высоким затратам на его разработку и временным задержкам при выводе продукта на рынок. Исследование, проведенное Национальным институтом стандартов и технологий, показало, что недостаточное тестирование программного обеспечения обходится экономике США в 59,5 миллиардов долларов в год, т. е. Около 0,6% от ее ВВП [1.a.1.]. Количество ошибок, обнаруженных после завершения работы над кодом продукта, может ошеломить разработчиков проектов, если программное обеспечение не было тщательно протестировано. Например, комитет проекта Mozilla признал, что каждый день они получают почти 300 ошибок, которые требуют исправления [2.]. Поэтому важно иметь методы, которые могут помочь разработчикам быстро находить файлы с ошибками и быстрее устранять ошибки. Эти цифры подтверждают тот факт, что тестирование и отладка программного обеспечения имеют первостепенное значение для разработки высококачественного программного обеспечения.

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

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

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

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

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

1. Основные принципы отладки и тестирования

1.1 Общая методика отладки программного обеспечения

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

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

1.2 Современное состояние технологии отладки программного обеспечения

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

Чтобы помочь разработчикам программного обеспечения в отладке программы во время процесса кодирования, было предложено много новых подходов. Кроме того, на сегодняшний день доступно большое количество коммерческих сред отладки. Интегрированные среды разработки обеспечивают способ поиска и исправления некоторых заранее определенных ошибок, зависящих от языка (например, пропущенных символов известного оператора, неопределенных переменных и т.д.) без необходимости компиляции. Одной из областей, которая привлекла внимание отрасли, является визуализация необходимых базовых программных конструкций как средства анализа программы [6.].

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

Цели и задачи тестирования программного обеспечения

Целью тестирования программного обеспечения является получение знания о том, работает ли программа корректно, а также исправление найденных ошибок для улучшения качества ПО. Тестирование программного обеспечения обычно составляет 40% бюджета на разработку программного обеспечения [14.]. С этой точки зрения продукт тестирования программного обеспечения является таким же, как и прочие продукты. Но в отличие от «материальных» товаров, у программного обеспечения есть другие проблемы. Пользователи могут не обнаруживать проблем с программным приложением, если эти проблемы не проявляются при определенных обстоятельствах. При работе с «материальным» продуктом, возможно, проблемы удастся выявить до их возникновения. Другими словами, до тех пор, пока определенные условия не проверены, программное обеспечение в целом работает нормально.

Таким образом, можно сказать, что проблемы в приложении возникают из-за слабости (неполноты) их тестирования. В связи с растущей сложностью и распространением приложений важность тестирования программного обеспечения постепенно возрастает. Основные задачи тестирования программного обеспечения [8.]:

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

Тестирование и отладка имеют ряд определенных различий. И тестирование, и отладка стремятся улучшить качество программного обеспечения, но в процессе отладки выявляются только программные ошибки, в то время как тестирование позволяет обнаружить также уязвимости программного обеспечения, которые включают аспекты той системы, в которой установлено и работает программное обеспечение [10.]. Другими словами, отладка обслуживает предопределенные недостатки, в то время как тестирование обнаруживает условия, которые затрудняют работу конечных пользователей. Проблема, выявленная в результате отладки, может привести к тому, что ожидаемая логика программного обеспечения не будет выполнена. С другой стороны, системные ошибки, которые выявляются при тестировании программного обеспечения, несут риски как для самих пользователей, так и для самого программного обеспечения. Программное обеспечение должно быть разработано и внедрено для предотвращения этих ошибок [11.]. Если программист используется в качестве тестера программного обеспечения, ошибка, скорее всего, не будет обнаружена при ее наличии [13.].

Как правило, перед кодированием программы анализ конструкции и проверка кода выполняются в рамках статического тестирования [13.]. Как только код написан, могут применяться различные другие методы статического анализа, основанные на исходном коде [14.]. Различные виды и этапы тестирования, предназначенные для разных уровней интеграции и различных режимов сбоев программного обеспечения, обсуждаются в большом количестве литературы [15., 16.]. Например, тестирование, проводимое на более поздних этапах (например, тесты внешних функций, системные тесты и т. д.) – это тестирование «черного ящика», основанное на внешних спецификациях, и, следовательно, не подразумевающее понимания реализаций детального кода. Как правило, системное тестирование направлено на ключевые аспекты продукта, такие как восстановление, безопасность, производительность, конфигурация оборудования, программного обеспечения и т. д. Тестирование в процессе производства и внедрения обычно включает определенный уровень критериев приемлемости для клиента [17.]. Многие компании-разработчики разрабатывают предварительные бета-программы для своих клиентов.

Тестирование программного обеспечения имеет следующий жизненный цикл:

  1. Анализ потребностей: необходимо выполнить этап анализа потребностей жизненного цикла тестирования программного обеспечения;
  2. Анализ проекта: на этом этапе специалисты по тестированию и дизайна определяют, какая часть проекта и какие параметры должны использоваться при тестировании;
  3. Дизайн тестирования: на этом этапе стратегия тестирования становится понятной;
  4. Запуск тестирования: запуск тестирования – любые ошибки будут сообщены разработчику;
  5. Отчет об испытаниях: после завершения испытаний последние результаты публикуются в форме отчета, который определяет, является ли программное обеспечение пригодным для использования или нет.

1.3 Современное состояние технологии тестирования программного обеспечения

Критика Дейкстры [18.], «Тестирование программ может использоваться для выявления наличия ошибок, но не для выявления их отсутствия», хорошо известна. С его точки зрения, любой объем тестирования представляет собой лишь небольшую выборку из всех возможных вычислений и поэтому никогда не является достаточным для обеспечения ожидаемого поведения программы при всех возможных условиях. Он утверждал, что «степень, в которой может быть установлена ​​корректность программы, является не просто функцией внешних спецификаций и поведения программы, а критически зависит от ее внутренней структуры». Однако тестирование стало предпочтительным процессом удовлетворения потребностей программного обеспечения. Это связано, прежде всего, с тем, что никакой другой подход, основанный на более формальных методах, не приблизился бы к обеспечению масштабируемости и удовлетворению интуитивных потребностей «разработчика» в программировании. Гамлет связал хорошее тестирование с измерением надежности тестируемого программного обеспечения в некотором статистическом смысле. Отсутствие или наличие сбоев, выявленных самим тестированием, не измеряет надежность программного обеспечения, если только не существует какого-либо способа количественно оценить свойства тестирования, чтобы убедиться, что адекватные параметры тестирования, включая тестируемость целевого программного обеспечения, были охвачены. Методы планирования тестирования, основанные на разделении функциональности, данных, рабочих профилей конечного пользователя [20.] и т.д. очень полезны и популярны в исследованиях тестирования и среди специалистов-практиков. Многие из современных технологий в тестировании основаны на этих идеях.

Как обсуждалось ранее, тестирование – это, по сути, выборка пространства выполнения программы. Следовательно, возникает естественный вопрос: когда мы должны прекратить тестирование? Учитывая то, что мы не можем реально показать, что в программе больше нет ошибок, мы можем использовать только эвристические аргументы, основанные на завершенности и изощренности усилий по тестированию, и тенденциях в результате обнаружения дефектов для того, чтобы доказать вероятность более низкого риска оставшихся дефектов. Примерами метрик, используемых в процессе тестирования [19.], которые нацелены на обнаружение дефектов и размер кода, являются: размер продукта и выпуска с течением времени, частота обнаружения дефектов с течением времени, отставание по дефектам с течением времени и так далее. Некоторые практические метрики, которые характеризуют процесс тестирования – прогресс тестирования во времени (запланированный, предпринятый, фактический), процент выполненных тестовых случаев и т.д. В некоторых организациях использование метрик покрытия тестов (например, охват кода) используется для описания завершенности тестирования. Использование методологии Ортогональной классификации дефектов [3.] позволяет дать более семантическую характеристику как природы обнаруженных дефектов, так и завершенности процесса тестирования.

Анализ исходного кода для выявления потенциальных дефектов является хорошо развитой отраслью разработки программного обеспечения [4.]. Типичный метод работы состоит в том, чтобы сделать целевой код доступным для инструмента анализа кода. Затем инструмент будет искать некий класс проблем и помечать их как потенциальных кандидатов для изучения и исправления. В анализе исходного кода есть явные преимущества: это можно сделать до того, как появится исполняемая версия программы. Определенный класс ошибок, например, утечки памяти, легче выявить при анализе, чем при тестировании. Неисправность легче локализовать, так как симптомы имеют тенденцию быть причиной. Типичный анализ выполняется с использованием компилятора или анализатора, привязанного к языку программы, который создает представление, такое как граф вызовов, граф управления или граф потока данных программы. Многие коммерческие и исследовательские инструменты доступны в этой области.

Любые действия с тестированием состоят из четырех основных частей: разработка тестового набора, создание тестового набора, выполнение тестового набора и отладка [13.]. Из-за большого объема необходимого тестирования большинство организаций переходят от тестирования в преимущественно ручном режиме к автоматизированному тестированию. Из-за сложности рассматриваемых вопросов наиболее легко поддающимся автоматизации является выполнение тестов. Это предполагает, что контрольные примеры уже определены и записаны вручную (или получены с помощью инструмента) и могут быть выполнены в автоматизированной среде выполнения тестов с точки зрения планирования, регистрации результатов (успех или неудача), захвата деталей отказавшей среды окружения, и так далее. Для тестирования, которое требует явного использования графических пользовательских интерфейсов, автоматизация выполнения тестовых примеров уже привела к значительному увеличению производительности в отрасли. Существует целый ряд коммерческих и исследовательских инструментов тестирования.

Автоматизация проектирования тестовых наборов (и, следовательно, создание тестовых наборов) – является еще одной областью для изучения [5.]. Чтобы автоматизировать разработку функциональных тестовых примеров, необходимо иметь формальное описание спецификаций поведения программного обеспечения, в результате чего получается модель поведения ПО. Как обсуждалось ранее, это формальное описание не охватывается типичными коммерческими организациями. В то время как использование технологии конечных автоматов [6.] начинает завоевывать популярность в сообществе валидации моделей, ее использование в более широком сообществе тестирования промышленного программного обеспечения в лучшем случае ограничено. Растущее принятие UML (Unified Modeling Language, рус. «унифицированный язык моделирования») разработчиками в качестве языка проектирования может предоставить возможность для получения более формального описания спецификаций программного обеспечения. Тем не менее, в UML все еще не хватает конструкций, чтобы быть эффективным языком для получения реалистичных спецификаций тестовых примеров [12.].

Для программного обеспечения, которое прошло через много версий, одним из острых вопросов была проверка спецификаций предыдущих релизов по сравнению с текущим [18.]. Обычно это делается посредством выполнения «регрессионных» тестовых случаев (которые использовались для проверки предыдущих релизов) по сравнению с текущим релизом. В большинстве реальных сред автоматическое отслеживание не установлено среди тестовых случаев (то есть никто не знает, почему тестовый пример был добавлен или он все еще действителен). Кроме того, связь между требованиями к коду и финальной реализацией не отслеживается между версиями. Следовательно, регрессионное тестирование не только проверяет, что более ранние спецификации все еще действительны, но также выявляет проблемы обратной совместимости. Хотя существует очевидная необходимость продолжать добавлять набор регрессионных тестов, исходя из опасений относительно совокупных спецификаций для текущей версии программы, собранная неадекватная информация делает невозможным сокращение набора регрессий по мере развития продукта [3.]. Это еще одна область, в которой может помочь проектирование автоматизированных тестовых наборов, поскольку тестовые наборы будут естественным образом связаны со спецификацией, а трассировка будет встроена.

2. Стратегии тестирования программного обеспечения

2.1 Метод черного ящика

Тестирование по методу черного ящика основано на предположении, что тест не знает содержимого и алгоритмов программного обеспечения, подразумевая только набор входных данных и предсказуемые выходные данные [4.]. Этот метод проводится командой специалистов по тестированию или конечными пользователями. Иногда его также называют функциональным тестом, который не имеет внутреннего механизма системы.

Этот метод включает в себя следующие техники:

  1. Разделение эквивалентности

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

  1. Анализ граничных значений

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

  1. Фаззинг

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

  1. Причинно-следственная диаграмма

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

  1. Тестирование ортогональных массивов

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

  1. Метод попарного тестирования

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

  1. Тестирование переходов состояний

Этот тип тестирования полезен для тестирования конечного автомата, а также для навигации по графическому интерфейсу пользователя.

Преимущества [5.]:

  1. Тестеры могут не иметь никаких специальных знаний конкретного языка программирования.
  2. Тестирование проводится с точки зрения пользователя.
  3. Тестирование помогает выявить любые неясности или несоответствия в спецификациях требований.
  4. Программист и тестер не зависят друг от друга.

Недостатки:

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

2.2 Метод белого ящика

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

Этот метод включает в себя следующие техники (см. рисунок 1):

Рисунок 1. Представление различных видов тестирования по методу белого ящика

1) Ручная имитация работы программы

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

2) Разбор кода

В этом процессе тестирования группа технических специалистов подробно разбирает код. Это один из видов техники полуформального изложения.

3) Формальные инспекции

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

4) Тестирование потоков управления

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

5) Тестирование базового пути

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

6) Тестирование потока данных

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

  1. Циклическое тестирование

Сосредоточено исключительно на валидности конструкции цикла.

Преимущества:

  1. Обнаруживает ошибку в скрытом коде, удаляя лишние строки кода.
  2. Максимальный охват достигается при написании тестового сценария [20.].
  3. Разработчик тщательно обосновывает причины реализации.

Недостатки:

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

2.3 Метод серого ящика

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

Этот метод включает в себя следующие техники:

  1. Тестирование ортогональных массивов

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

  1. Матричное тестирование

В матричном тестировании указывается отчет о состоянии проекта.

  1. Регрессионное тестирование

Если в программное обеспечение вносятся новые изменения, регрессионное тестирование подразумевает выполнение тестовых случаев.

  1. Тестирование шаблонов

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

Преимущества:

1. Данный метод обеспечивает совместное преимущество методов тестирования «черного ящика» и «белого ящика».

2. При тестировании по этому методу специалист может разработать отличные сценарии тестирования.

3. Беспристрастное тестирование.

Недостатки:

1. Тестовое покрытие в данном случае ограничено, так как доступ к исходному коду невозможен.

2. Многие пути программы остаются непроверенными.

3. Контрольные примеры могут быть избыточными.

Сравнение методов тестирования приведено в таблице ниже.

Сравнение методов тестирования по некоторым критериям

Номер

критерия

Метод черного ящика

Метод белого ящика

Метод серого ящика

1

Анализирует только фундаментальные аспекты, т. е. нет знания внутренней работы

Полное знание внутренней работы

Частичное знание внутренней работы

2

Это наименее исчерпывающий и трудоемкий процесс

Потенциально наиболее исчерпывающий и отнимающий много времени

Среднее между критериями для черного и белого ящиков

Продолжение таблицы

Номер

критерия

Метод черного ящика

Метод белого ящика

Метод серого ящика

3

Не подходит для тестирования алгоритмов

Подходит для тестирования алгоритмов (любых)

Не подходит для тестирования алгоритмов

4

Степень точности тестирования низкая

Степень точности тестирования высокая

Степень точности тестирования средняя

5

Выполняется конечными пользователями, а также специалистом по тестированию и разработчиками (приемочное тестирование пользователя)

Выполняется специалистом по тестированию и разработчиками

Выполняется конечными пользователями, а также специалистом по тестированию и разработчиками (приемочное тестирование пользователя)

3. Механизмы отладки и тестирования на конкретных примерах

3.1 Особенности современных сред разработки программ

Основным предназначением интегрированных сред разработки программ, а также их главным преимуществом можно назвать повышение производительности труда программистов и автоматизацию создания исходных кодов программ. Интегрированные среды повышают производительность за счет сокращения времени установки, увеличения скорости выполнения задач разработки, возможности поддержки и стандартизации процесса разработки [12.].

  • Ускоренная настройка. Без графического интерфейса, предоставляемого визуальной интегрированной средой, разработчикам придется тратить время на настройку нескольких инструментов разработки. Благодаря возможностям интегрированной среды разработчики получают один и тот же набор функций в одном месте без необходимости постоянного переключения инструментов.
  • Ускоренные задачи разработки. Более тесная интеграция всех задач разработки повышает производительность труда разработчиков. Например, код может быть проанализирован лексически и синтаксически во время редактирования, если среда обеспечивает мгновенную обратную связь при появлении синтаксических ошибок. Разработчикам не нужно переключаться между приложениями для выполнения задач. Кроме того, инструменты и функции интегрированной среды разработки помогают разработчикам оптимизировать ресурсы, предотвращать ошибки и использовать наиболее рациональные способы решения задач. Кроме того, интегрированные среды разработки улучшают мыслительный процесс, заставляя разработчиков думать о своих действиях с точки зрения всего жизненного цикла разработки, а не как серии отдельных задач.
  • Непрерывное обучение. Поддержка проектов и самообразование при помощи интегрированных сред – еще одно преимущество. Например, разделы справки или помощи в современных средах разработки постоянно обновляются, а также появляются новые образцы кода, шаблоны проектов и т.д. Программисты, которые постоянно учатся и знакомятся с лучшими практиками, с большей вероятностью будут приносить пользу команде и предприятию и повышать производительность.
  • Стандартизация. Интерфейс интегрированной среды стандартизирует процесс разработки, что помогает разработчикам более комфортно работать вместе и быстрее привлекать к совместному сотрудничеству новых специалистов.

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

Некоторые современные интегрированные среды предназначены для определенного языка программирования или набора языков, предоставляя набор функций, который согласуется с особенностями этого языка [11.]. Например, среда Xcode поддерживается только для языков Objective-C и Swift. Однако также существует много так называемых мультиязычных сред, таких как Eclipse (для языков C, C ++, Python, Perl, PHP, Java, Ruby и других), Komodo (Perl, Python, Tcl, PHP, Ruby, Javascript и других) и NetBeans (Java, JavaScript, PHP, Python, Ruby, C, C ++ и других). Поддержка альтернативных языков часто обеспечивается плагинами. Например, Flycheck является расширением проверки синтаксиса для GNU Emacs с поддержкой 39 языков.

Существует множество различных интегрированных сред, учитывающих различные способы работы разработчиков и различные типы кода, которые они создают. Существуют среды, разработанные для разработки на одном конкретным языком, облачные интегрированные среды разработки, или среды, предназначенные исключительно для разработки мобильных приложений или для HTML, а также среды, предназначенные специально для разработки для Apple или Microsoft.

Как правило, большинство современных интегрированных сред снабжены графическими интерфейсами. При этом среда может быть автономным приложением, а в некоторых случаях она может быть частью существующего и совместимого приложения. Например, язык программирования BASIC можно использовать вместе с приложениями Microsoft Office, и можно написать программу WordBasic в приложении Microsoft Word. Современные интегрированные среды стремятся обеспечить удобную среду программирования для современных языков, таких как Visual Basic, Java, C# и многих других.

Вряд ли есть какое-либо определение, которое четко проводит границу между интегрированными средами и другими более широкими средами разработки программного обеспечения. Поэтому некоторые среды могут содержать компилятор, а некоторые – интерпретатор, в то время как в некоторых случаях интегрированные среды могут использоваться как компиляторы, так и интерпретаторы [7.]. Некоторыми примерами таких сред, которые поддерживают как компилятор, так и интерпретатор, являются Microsoft Visual Basic и Eclipse, в то время как другие, такие как SharpDeveloper и Lazarus, не допускают и того, и другого. В некоторых случаях для упрощения построения графического интерфейса пользователя в среды могут быть интегрированы системы контроля версий и различные другие инструменты.

Многоязычные интегрированные среды, такие как Eclipse, NetBeans, Komodo, Aptana и Geany, поддерживают несколько языков программирования.

Eclipse: поддерживает C, C++, Python, Perl, PHP, Java, Ruby и другие. Этот бесплатный редактор с открытым исходным кодом является моделью для многих сред разработки. Eclipse начинался как среда разработки Java и расширился с помощью плагинов. В настоящее время Eclipse управляется и направляется Консорциумом Eclipse.org.

NetBeans: поддерживает Java, JavaScript, PHP, Python, Ruby, C, C++ и другие языки программирования. Эта среда также бесплатная и с открытым исходным кодом. Все ее действия определены модулями, каждый из которых обеспечивает четко определенную функцию. Поддержка других языков программирования может быть добавлена ​​путем установки дополнительных модулей.

Komodo: поддерживает Perl, Python, Tcl, PHP, Ruby, Javascript и другие. Эта среда предназначена для промышленной разработки и имеет более высокую цену.

Aptana: поддерживает HTML, CSS, JavaScript, AJAX и другие языки программирования за счет использования специализированных плагинов. Эта среда является довольно популярным выбором для разработки веб-приложений.

Geany: поддерживает C, Java, PHP, HTML, Python, Perl, Pascal и многие другие языки программирования. Это настраиваемая среда с большим набором плагинов.

В последние годы облачные интегрированные среды разработки начинают становиться мейнстримом. Возможности этих веб-ориентированных сред быстро растут, и большинству крупных компаний-разработчиков, скорее всего, придется предлагать свою среду, чтобы быть конкурентоспособным. Облачные среды предоставляют разработчикам доступ к своему коду из любой точки мира. Например, Nitrous – это облачная платформа среды разработки, которая поддерживает Ruby, Python, Node.js и другие. Cloud9 поддерживает более 40 языков, включая PHP, Ruby, Python, JavaScript с Node.js и Go. Heroku – еще одна популярная облачная платформа разработки, поддерживающая несколько языков программирования.

Ниже перечислены среды разработки, предназначенные для тех, кто работает в средах Microsoft или Apple:

Visual Studio: поддерживает Visual C++, VB.NET, C#, F# и другие языки программирования. Visual Studio является средой компании Microsoft и предназначена для создания приложений для платформы Microsoft [8.].

MonoDevelop: поддерживает C / C++, Visual Basic, C# и другие языки .NET.

Xcode: поддерживает языки Objective-C и Swift, а также API-интерфейсы Cocoa и Cocoa Touch. Эта среда предназначена только для создания приложений для iOS и Mac и включает в себя симулятор iPhone / iPad и конструктор графического интерфейса пользователя.

Espresso: поддерживает HTML, CSS, XML, JavaScript и PHP. Это инструмент для веб-разработчиков Mac.

Coda: поддерживает PHP, JavaScript, CSS, HTML, AppleScript и API Cacao.

Учитывая цели данной курсовой работы, для дальнейшего рассмотрения был выбран язык программирования Cи как один из наиболее популярных среди современных языков программирования, предназначенных для обучения [9.]. Выбор среды разработки для реализации программного приложения основывается на том, что выбираемая среда должна быть простой в использовании, чтобы позволить сосредоточиться на изучении концепций программирования, а также многофункциональной, для того, чтобы научиться создавать простые программы для решения прикладных задач [10.].

В качестве интегрированной среды разработки для выполнения отладки были выбраны следующие среды:

  • Dev-C++, написанная на языке программирования Delphi для Windows, которая является легковесной средой, бесплатной и с открытым исходным кодом, которой требуется всего пару минут для установки;
  • Visual Studio Community 2017, современная свободно распространяемая интегрированная среда, предназначенная для разработки программного обеспечения в учебных целях. Visual Studio включает в себя редактор исходного кода с поддержкой технологии IntelliSense и возможностью простейшего рефакторинга кода. Встроенный отладчик может работать как отладчик уровня исходного кода, так и отладчик машинного уровня. Присутствует удобный редактор форм для упрощения создания графического интерфейса приложения, веб-редактор, дизайнер классов и дизайнер схемы базы данных. Visual Studio позволяет создавать и подключать сторонние дополнения (плагины) для расширения функциональности практически на каждом уровне, включая добавление поддержки систем контроля версий исходного кода.

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

3.3 Механизм отладки в Dev-C++

Проект – это центр для управления исходными файлами и опциями внутри интегрированной среды разработки. Он помогает перемещаться по коду и легко устанавливать различные параметры, например, тип программы, которую необходимо создать (GUI, консоль, DLL ...).

Проект группирует несколько файлов с общей целью. Создаваемый в этом разделе проект будет включать файл с метаданными о проекте (.dev для Dev-C++ или .sln для Visual Studio), несколько проектных файлов (объектный код, файлы связывания и т.д.) и файл с исходным кодом (только этот файл должен быть явно создан программистом, остальные файлы автоматически генерируются средой разработки.

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

После запуска среды необходимо создать проект соответствующими командами меню, после чего ввести его название, выбрать язык программирования, а также тип создаваемого приложения. На рисунке 2 создается консольное приложение на языке Си в среде разработки Dev-C++.

Необходимо также выбрать папку для хранения файлов в следующем окне. Каждый проект удобно хранить в отдельной папке.

После указания папки, в которой будет сохранен файл конфигурации проекта (.dev), в среде создается базовый файл исходного кода (по умолчанию main.c). Эти файлы не сохраняются в папке проекта, пока программист не сохранит или не скомпилирует программу.

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

В окне проводника файлов отображается название проекта и включенные файлы. Вкладка Project (Проект) обычно содержит один файл с исходным кодом программы. На этой панели можно найти две дополнительные вкладки: Классы (Classes) и Отладка (Debug). Вкладка Classes отображает функции программы. Вкладка Debug показывает наблюдаемые переменные в процессе отладки.

Рисунок 2 – Параметры создания проекта в среде Dev-C++

Окно «Результаты» используется для представления результатов действий среды: ошибок компиляции, директив компиляции, команд отладки и т.д. Редактор исходного кода показывает код программы.

Файлы проекта сохраняются при сохранении файла исходного кода. Остальные файлы проекта сохраняются при компиляции приложения в папке проекта.

Как только проект будет создан, можно начать писать программу. Например, программа HelloWorld на языке Си продемонстрирована на рисунке 3.

Рисунок 3 – Программа HelloWorld на языке Си в среде Dev-C++

Для запуска программы исходный код должен быть скомпилирован и скомпонован. Dev-C++ выполняет весь процесс после нажатия на кнопку компиляции «Compile» (или Ctrl + F9).

Во время выполнения процесса компиляции и компоновки в среде IDE отображается диалоговое окно со связанной информацией. Если процесс успешен, в окне отображается сообщение «Готово».

Лог компиляции продемонстрирован на рисунке 4. После этого процесса легко убедиться, что все описанные ранее файлы проекта были созданы, в том числе исполняемый (exe) файл программы.

Ошибки компиляции – это ошибки, обнаруженные компилятором. Их также называют ошибками времени выполнения. Чтобы исправить все ошибки компиляции, рекомендуется исправить первую и затем заново скомпилировать программу, поскольку следующие ошибки часто являются неправильными разделами кода, которые компилятор не может интерпретировать как результат первой ошибки. Dev-C++ подчеркивает красной строкой кода, где была обнаружена ошибка компиляции. Вкладка «Компиляция» окна «Результаты» содержит подробное описание ошибки. Журнал компиляции показывает сообщение об ошибке, выданное программой компиляции (рисунок 5).

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

В результате процесса линковки создается исполняемая программа. Чтобы запустить эту программу, необходимо нажать кнопку «Выполнить» (Ctrl + F10). Кроме того, можно найти exe-файл в папке проекта и дважды щелкнуть по нему.

Рисунок 4 – Лог компиляции Dev-C++

Рисунок 5 – Сообщение об ошибке компиляции в среде Dev-C++

Разработка синтаксически правильной программы не означает, что она выполняет необходимые процедуры. Сложные программы подвержены ошибкам, и обычно логика, реализованная в исходном коде, не приводит к ожидаемому поведению. Эти ошибки называются ошибками выполнения или логики, так как они обнаруживаются при запуске программы. Поэтому может потребоваться изменить исходный код и повторить процедуру компиляции и компоновки. В IDE имеется отладчик, который является вспомогательным инструментом для поиска ошибок времени выполнения. Чтобы использовать отладчик, необходимо изменить параметры компилятора, включив в него отладочную информацию и исполняемые файлы («Инструменты» -> «Параметры компилятора» -> «Компилятор»). Это делается путем добавления параметра –g к вызовам компилятора и компоновщика (рисунок 6).

Рисунок 6 – Опции компилятора для включения отладки в среде Dev-C++

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

3.4 Юнит-тестирование в Visual Studio

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

В этом подразделе рассматривается пример простейшего юнит-теста для кода, написанного на языке C#, в среде разработки Visual Studio. Пусть имеется метод, который рассчитывает температуру в градусах Фаренгейта для заданной температуры в градусах Цельсия. Код, для которого необходимо создать модульный тест, приведен в листинге 1.

Листинг 1. Исходный код класса с методом перевода температуры из градусов Фаренгейта в градусы Цельсия

public static class ConversionHelpers

{

private const double F_MULTIPLIER = 1.8;

private const int F_ADDITION = 32;

public static double ToFahrenheit(double celsius)

{

return celsius * F_MULTIPLIER + F_ADDITION;

}

}

Для создания юнит-теста необходимо его добавить в решение. На рисунке 7 показано, что в среде Visual Studio Community есть возможность добавить шаблон проекта Unit Test.

Рисунок 7 – Создание проекта юнит-тестирования в среде Visual Studio

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

Рисунок 8 – Проект юнит-тестирования в созданном решении

Чтобы эффективно протестировать класс, содержащий метод, который конвертирует градусы Цельсия в градусы Фаренгейта, нужно сослаться на этот класс в проекте юнит-тестирования. Для этого необходимо щелкнуть правой кнопкой мыши по проекту Unit Test и добавить ссылку на проект, содержащий класс, который нужно протестировать (рисунок 9).

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

Листинг 2. Исходный код юнит-теста

[TestClass]

public class ConversionHelperTests

{

[TestMethod]

public void Test_Fahrenheit_Calc()

{

var celsius = -7.0;

var expectedFahrenheit = 19.4;

var result = ConversionHelpers.ToFahrenheit(celsius);

Assert.AreEqual(expectedFahrenheit, result);

}

}

Рисунок 9 – Ссылка на тест

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

Для запуска в меню необходимо выбрать «Windows», а затем «Test Explorer» или удерживать нажатыми клавиши «Ctrl E, T». В «Text Explorer» нужно далее нажать на зеленую кнопку воспроизведения, чтобы запустить тест и увидеть его результаты (Рисунок 10).

Рисунок 10 – Запуск юнит-теста

Из результатов, отображаемых в «Test Explorer», можно легко увидеть, какие тесты не были пройдены, а какие пройдены. Из рассмотренного выше довольно простого теста в листинге 2 можно понять, что тест прошел легко и что ожидаемый результат действительно был реальным результатом теста. Этот юнит-тест сравнивает два типа двойных значений для точного равенства. Метод Assert.AreEqual имеет перегрузку, которая принимает в качестве параметра значение ошибки.

ЗАКЛЮЧЕНИЕ

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

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

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

Кроме того, в работе были рассмотрены механизмы отладки и тестирования на простейших примерах. В качестве интегрированных сред были использованы Dev-C++ с языком программирования Си для отладки; Visual Studio 2017 Community с языком программирования C# для юнит-тестирования.

Таким образом, цели и задачи курсовой работы выполнены в полном объеме.

СПИСОК ИСПОЛЬЗОВАННЫХ ИСТОЧНИКОВ

        1. Арсеновски, Даниэль Рефакторинг в C# и ASP.NET для профессионалов / Даниэль Арсеновски. - М.: Вильямс, 2010. - 528 c.
        2. Вирт Н. Алгоритмы и структуры данных. Новая версия для Оберона / Н. Вирт; пер. Д. Б. Подшивалов. - 2-е изд., испр. - М.: ДМК Пресс, 2012. – 272 с.
        3. Давыдов В.Г. Visual С++. Разработка Windows-приложений с помощью MFS и API функций / В.Г. Давыдов – СПб.: БХВ – Петербург, 2008. – 576 с.
        4. Демидович Е.М. Основы алгоритмизации и программирования. Язык СИ, учебное пособие / Е. М. Демидович. – 2-е изд., испр. и доп. – СПб.: БХВ – Петербург, 2008. – 440 с.
        5. Касперски, Крис Техника отладки программ без исходных текстов / Крис Касперски. - М.: БХВ-Петербург, 2005. - 165 c.
        6. Керниган, Брайан Практика программирования / Брайан Керниган , Роб Пайк. - М.: Вильямс, 2015. - 288 c.
        7. Кнут Д. Искусство программирования // The art of computer programming: [в 3 т.]. Т.1. Основные алгоритмы / Д. Кнут; ред. Ю. В. Козаченко. – 3-е изд. – М.: Вильямс, 2014. 720 с.
        8. Колдаев В.Д. Основы алгоритмизации и программирования: Учебное пособие / Колдаев В.Д; под ред. проф.Л.Г. Гагариной - М.: ИД ФОРУМ, НИЦ ИНФРА-М, 2016. - 416 с.
        9. Кон, Майк Пользовательские истории. Гибкая разработка программного обеспечения / Майк Кон. - Москва: СПб. [и др.] : Питер, 2012. - 256 c.
        10. Костельцев А. GTK+. Разработка переносимых графических интерфейсов / А. Костельцев – И.: Санкт-Петебург, 2013. – 368 с.
        11. Мэйерс, Скотт Наиболее эффективное использование С++. 35 новых рекомендаций по улучшению ваших программ и проектов / Скотт Мэйерс. - М.: ДМК Пресс, 2014. - 298 c.
        12. Ошероув, Рой Искусство автономного тестирования с примерами на С# / Рой Ошероув. - М.: ДМК Пресс, 2016. - 360 c.
        13. Поляк, Б. Т. Введение в оптимизацию / Б.Т. Поляк. - М.: Ленанд, 2014. - 392 c.
        14. Рэшка, Дж. Тестирование программного обеспечения / Дж. Рэшка. - М.: ЛОРИ, 2013. - 898 c.
        15. Троелсен Э. Язык программирования C# 5.0 и платформа .NET 4.5 / Э. Троелсен, 6-е изд. – М.: Издательский дом «Вильямс», 2013. – 1312 с.
        16. Фаулер, Мартин Рефакторинг. Улучшение существующего кода / Мартин Фаулер. - М.: Символ-плюс, 2008. - 432 c.
        17. Хант, Э. Программист-прагматик. Путь от подмастерья к мастеру / Э. Хант, Д. Томас. - М.: ЛОРИ, 2016. - 270 c.
        18. Хоп, Грегор Шаблоны интеграции корпоративных приложений / Грегор Хоп, Бобби Вульф. - М.: Вильямс, 2015. - 672 c.
        19. Шилдт Г. Полный справочник по С#, 4-ое издание / Г. Шилдт; пер. с англ. – М.: Издательский дом «Вильямс», 2015. – 704 с.
        20. Эванс, Эрик Предметно-ориентированное проектирование (DDD). Структуризация сложных программных систем / Эрик Эванс. - М.: Вильямс, 2015. - 448 c.