Главная | Обратная связь | Поможем написать вашу работу!
МегаЛекции

Система расчленяется только по одному, постоянному для всех уровней, признаку.




Рис.16. Граф программной системы

 

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

Соглашения об именовании данных, классов и методов сводятся к следующему.

Имя переменной должно полно и точно описывать ее сущность. Оно может состоять из нескольких слов, причем без сокращений. Например, trainVelocity (скорость поезда), currentDate (текущая дата) или startTime и т.д. вместо vel, date или time. Такие имена называют мнемоническими. Они обозначают объект, а не как его обрабатывают. Длина имени может быть пределах от 10 до 16 символов. Более длинные сложнее читать и набирать.

Короткие имена обычно имеют индексы переменных. Их тоже предлагается обозначать не i, j или k, а, например, eventIndex или masIndex. Булевы переменные часто обозначают условие выполнения некоторого блока или цикла. Их целесообразно называть по смыслу этого условия: done, error, found и т.д. или vipolnit, oshibka, naideno.

Для некоторых имен во многих организациях принимают соглашения об именовании переменных, классов и методов. Например, могут использоваться префиксы in, out, doc и др. для обозначения вводимых, выводимых данных и документов (например, inName, docActive). Соглашения полезны в следующих случаях.

1) Над проектом работает несколько программистов;

2) Программу будут сопровождать и изменять другие программисты;

3) Программа очень большая, поэтому всю ее один человек не может охватить, а вынужден рассматривать по частям;

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

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

Например, как принято в java, имена переменных должны начинаться со строчной буквы, а методов и классов – с прописной. При этом наименования типов более общие, а переменных – длиннее и конкретнее.

Например.

Length dlina, lenKatet;

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

Еще одна рекомендация касается констант. Все ведущие программисты считают, что необходимо избегать так называемых «магических» (явных) констант. Например,

For (int i = 0; i< 99; i++){

}

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

For (int i = 0; i< max_Numbers; i++){

}

или

 

For (int i = 0; i< massiv.length; i++){

}

В Java именованные константы описываются с атрибутом final.

 

1.1.5. Стандарты программирования

 

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

 

Ожидание изменений

 

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

Существует два вида изменений:

a) Усовершенствование кода программы (рефакторинг);

b) Добавление новой функциональности (реинжениринг).

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

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

Основная цель рефакторинга — сделать код программы более простым для понимания.

Его следует отличать от оптимизации производительности. Последняя не изменяет поведение программы, а только ускоряет её работу. Но оптимизация часто затрудняет понимание кода.

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

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

1) необходимо добавить новую функцию, которая недостаточно укладывается в принятое архитектурное решение;

2) необходимо исправить ошибку, причины возникновения которой неясны;

3) преодоление трудностей в командной разработке, которые обусловлены сложной логикой программы.

При рефакторинге часто полагаются на интуицию, основанную на опыте. Тем не менее, он требуется при наличии следующих проблем в коде программы:

1) дублирование кода;

2) длинный метод;

3) большой класс;

4) длинный список параметров;

5) «жадные» функции — метод, который часто обращается к данным другого объекта;

6) избыточные временные переменные;

7) классы данных;

8) несгруппированные данные.

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

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

Рефакторинг может быть связан с:

a) перемещением поля из одного класса в другой,

b) вынесением фрагмента кода из метода и превращением его в самостоятельный метод или

c) перемещением кода по иерархии классов.

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

Наиболее часто употребляемые методы рефакторинга:

  • Изменение сигнатуры метода (Change Method Signature)
  • Инкапсуляция поля (Encapsulate Field)
  • Выделение класса (Extract Class)
  • Выделение интерфейса (Extract Interface)
  • Выделение локальной переменной (Extract Local Variable)
  • Выделение метода (Extract Method)
  • Генерализация типа (Generalize Type)
  • Встраивание (Inline)
  • Введение фабрики (Introduce Factory)
  • Введение параметра (Introduce Parameter)
  • Подъём метода (Pull Up Method)
  • Спуск метода (Push Down Method)
  • Переименование метода (Rename Method)
  • Перемещение метода (Move Method)
  • Замена условного оператора полиморфизмом (Replace Conditional with Polymorphism)
  • Замена наследования делегированием (Replace Inheritance with Delegation)
  • Замена кода типа подклассами (Replace Type Code with Subclasses)

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

Инкапсуляция поля. В случае, если у класса имеется открытое поле, необходимо сделать его закрытым и обеспечить методы доступа. После Инкапсуляции часто применяется перемещение метода.

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

a) если фрагмент кода требует комментария о том, что он делает, то он должен быть выделен в отдельный метод.

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

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

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

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

a) вначале создается базовый класс и нужное число подклассов;

b) выполняется оптимизация условного оператора путем Выделения метода;

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

d) выбор одного из подклассов, конкретизация в нем полиморфного метода базового класса и перемещение в него тела соответствующей ветви условного оператора;

e)повторение предыдущего действия для каждой ветви условного оператора;

f) замена условного оператора вызовом полиморфного метода базового класса.

Основные проблемы, возникающие при проведении рефакторинга:

· связанные с базами данных;

· изменение интерфейсов;

· трудности при изменении дизайна.

Основные показатели и результаты рефакторинга:

  • скорость;
  • отмена модификаций;
  • интеграция с другими средствами.

Реинжиниринг программного обеспечения — процесс создания новой функциональности или устранения ошибок путем глобального изменения, но на основе уже имеющегося в эксплуатации программного обеспечения. Процесс реинжиниринга описан Чиковски и Кроссом в их труде 1990 года, как «The examination and alteration of a system to reconstitute it in a new form». Он является изменением системы после проведения обратного инжиниринга.

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

1) обычному программисту сложно разобраться в чужом исходном коде;

2) реинжиниринг, чаще всего, дороже разработки нового программного обеспечения, так как требуется убрать ограничения предыдущих версий, но при этом оставить совместимость с ними;

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

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

Обратная разработка (обратный инжиниринг, реверс-инжиниринг; англ. reverse engineering) — исследование некоторой готовой программы, а также документации на нее с целью понять принцип ее работы. Например, чтобы обнаружить недокументированные возможности, сделать изменение или воспроизвести программу с аналогичными функциями, но без прямого копирования.

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

В настоящее время под словами «reverse engineering» чаще всего понимается процесс, при котором одна группа разработчиков анализирует машинный код, составляет алгоритм этой программы на псевдокоде либо, если программа является драйвером какого-либо устройства. После получения спецификаций другая группа разработчиков пишет собственный драйвер на основе полученных спецификаций или алгоритмов. Такой подход позволяет избежать обвинений в нарушении авторских прав на исходную программу, так как по законам, к примеру, в США, подпадает под понятие «fair use», то есть добросовестного использования оригинальной программы. Результат обратной разработки редко идентичен оригиналу, что и позволяет избежать ответственности перед законом.

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

С развитием Интернета популярные операционные системы и программы часто исследуются на предмет обнаружения в них уязвимостей или т. н. «дыр». В дальнейшем найденные дыры могут использоваться для получения несанкционированного доступа к удаленному компьютеру или компьютерной сети. C другой стороны, обратная разработка применяется при исследовании антивирусными компаниями вредоносного ПО c целью добавления его сигнатур в базы своих продуктов.

Одним из широко известных примеров обратной разработки является исследование BIOS персонального компьютера IBM, ставшее серьезным шагом на пути развития производства IBM-совместимых компьютеров сторонними производителями. Появление сервера Samba (входящего в состав ОС GNU/Linux и работающего с серверами на базе ОС Windows) также потребовало обратной разработки используемого Microsoft протокола SMB. Наличие многих ICQ-клиентов также привело к обратной разработке протокола ICQ.

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

1. Анализ обмена данными, наиболее распространённый в обратной разработке протоколов.

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

3. Декомпиляция машинного или байт-кода программы для создания исходного кода на некотором языке программирования высокого уровня.

Анализ исходного кода. С широким применением методологии IDEF (моделирования процессов в сложных производственных системах) связано возникновение основных идей популярного понятия — BPR (бизнес-процесс-реинжиниринг). Смысл этого реинжиниринга в следующих основных этапах:

  • определение оптимального (идеального) вида бизнес-процесса (в первую очередь основного);
  • определение наилучшего (по средствам, времени, ресурсам и т.п.) способа перевода существующего бизнес-процесса в оптимальный.

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

1.3. Конструирование с возможностью проверки

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

Наиболее распространенными техниками, направленными на достижение такого результата конструирования, являются:

a) обзор и оценка кода;

b) модульное тестирование;

c) структурирование кода совместно с применениям автоматизированных средств тестирования;

d) ограниченное применение сложных или тяжелых для понимания языковых структур.

Обзор кода (code review) – один из самых старых и надежных методов выявления дефектов. Он основан на простой идее, используемой во множестве других сфер человеческой деятельности. Если проблему будут решать и обсуждать несколько человек, то они смогут предложить лучшее решение и избежать множества ошибок. Когда человек работает один, то он может даже не догадываться, что допускает явную ошибку или реализует что-то неоптимальным способом.

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

Как правило, обзор хорошо работает, так как программисты намного легче замечают ошибки в чужом коде. Кроме того он может служить для обучения. Участники обсуждения узнают новые приемы программирования, новые шаблоны, учатся красиво оформлять код. Более подробно с методикой обзора кода можно познакомиться в замечательной книге Стива Макконнелла "Совершенный код" (Steve McConnell, "Code Complete"). Он используется при парном программировании и официальных проверках программ.

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

Эффективность обзоров анализировалась разными авторами. Их результаты показывают, что обзор позволяет обнаруживать до 60 – 65 % дефектов. В среднем выявляется порядка 50 % ошибок. Размер кода влияет на эффективность. Обычно он не должен превышать 200 – 400 строк. Особенно это важно для критических приложений (определяющих безопасность).

Обзор кода выполняется одним из двух основных способов.

a) Формального анализа;

b) Быстрого обзора.

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

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

a) «Через плечо», при котором разработчик следит через плечо проверяющего, когда тот просматривает код;

b) С помощью электронной почты, по которой отсылается результат проверки;

c) Парным программированием, при котором один и тот же код пишется двумя программистами. Оно будет рассмотрено позднее;

d) С использованием специализированных программных инструментов, например, IRC.

Быстрый обзор, как правило, позволяет найти меньше ошибок, чем формальный анализ, но он является более быстрым и экономически эффективным.

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

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

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

Некоторые считают программные метрики и обратное проектирование формами статического анализа. При этом получение метрик и статический анализ часто совмещаются, особенно при создании встраиваемых систем.

В последнее время статический анализ используется для ПО, систем высокой надежности, особенно критичных для жизни (safety-critical). Он также применяется для поиска кода, потенциально содержащего уязвимости (иногда это применение называется Static Application Security Testing, SAST).

Статический анализ используется для критичного ПО в следующих областях:

1) в медицине,

2) для атомных станций и систем защиты реактора,

3) в авиации,

4) в автомобильном или железнодорожном транспорте.

По данным VDC на 2012 год, примерно 28 % разработчиков встраиваемого ПО применяют средства статического анализа, а 39 % собираются начать их использование в течение 2 лет.

Большинство компиляторов (например, GNU C Compiler) выводят на экран «предупреждения» (англ. warnings) — сообщения о том, что код, будучи синтаксически правильным, скорее всего, содержит ошибку. Например:

int x;int y = x+2; // Переменная x не инициализирована!

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

Типы ошибок, обнаруживаемых статическими анализаторами:

a) Неопределённое поведение — неинициализированные переменные, обращение к NULL-указателям. О простейших случаях сигнализируют и компиляторы.

b) Нарушение правил пользования библиотекой. Например, в Си для каждого fopen нужен fclose. Если файловая переменная теряется раньше, чем файл закрывается, анализатор может сообщить об ошибке.

c) Типичные сценарии, приводящие к недокументированному поведению. Стандартная библиотека языка Си известна большим количеством неудачных технических решений. Некоторые функции, например, gets в небезопасны.

d) Переполнение буфера — когда компьютерная программа записывает данные за пределами выделенного в памяти буфера.

e) Ошибки в повторяющемся коде. Многие программы исполняют несколько раз один и тот же фрагмент с разными аргументами. Такой фрагмент фрагменты не нужно оформить в виде метода.

Инструменты статического анализа Java:

· FindBugs (FindBugs on sf)

· Parasoft JTest (англ.)русск.

· fbinfer.

Модульное или юнит-тестирование — процесс, позволяющий проверить корректность отдельных модулей исходного кода программы.

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

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

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

При этом в ходе модульного тестирования решаются четыре основные задачи.

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

2. Поддержка разработки и рефакторинга низкоуровневой архитектуры системы и межмодульного взаимодействия. Такая задача свойственна «легким» методологиям типа XP, в которых применяется принцип тестирования перед разработкой (Test-driven development). При этом основным источником требований для программного модуля является тест, написанный заранее.

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

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

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

1. Не существует единых принципов определения того, что в точности является отдельным модулем.

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

Обычно за тестируемый модуль принимается либо программный модуль (единица компиляции) в случае, если система разрабатывается на процедурном языке программирования, либо класс, если система разрабатывается на объектно-ориентированном языке.

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

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

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

· инкапсуляции, в результате которых, например, сокрытые данные класса оказывается недоступными при помощи соответствующих публичных методов;

· наследования, при наличии которых схема наследования блокирует важные данные или методы от классов-потомков;

· полиморфизма, при которых полиморфное поведение класса оказывается распространенным не на все возможные классы;

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

Модульное тестирование не эффективно в следующих случаях

a) Для сложных кодов. Тестирование — комбинаторная задача. Например, каждое возможное значение булевской переменной потребует двух тестов: один на вариант TRUE, другой — на вариант FALSE. В результате на каждую строку исходного кода потребуется 3−5 строк теста. Как и любая технология тестирования, модульное тестирование не позволяет отловить все ошибки программы.

b) Если результат известен приблизительно. Например, в математическом моделировании. Бывает сложно подобрать тесты для каждой из ветвей программы, сложно сказать, верен ли результат, обеспечивается ли точность, и т. д. Во многих случаях качество моделирования определяется приблизительно, и последний результат записывается как «опорный». Если найдено расхождение, новый результат проверяют вручную и выясняют, какой лучше: старый или новый.

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

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

e) Проблемы с объектами-заглушками, которые заменяются работающими модулями. При этом могут измениться межмодульные интерфейсы.

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

Для большинства популярных языков программирования высокого уровня существуют инструменты и библиотеки модульного тестирования. Для Java это:

· JUnit JUnit.org

· TestNG testNG.org

· JavaTESK UniTESK.ru

Поделиться:





Воспользуйтесь поиском по сайту:



©2015 - 2024 megalektsii.ru Все авторские права принадлежат авторам лекционных материалов. Обратная связь с нами...