5 уровни тестирования понятие модуля важность изоляции при тестировании

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

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

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

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

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

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

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

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

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

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

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

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

При этом подходе возникают два вопроса: 1. «Что делать, когда тестируемый модуль вызывает модуль более низкого уровня (которого в данный момент еще не существует)?» и 2. «Как подаются тестовые данные?»

Ответ на первый вопрос состоит в том, что для имитации функций недостающих модулей программируются модули – «заглушки», которые моделируют функции отсутствующих модулей.

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

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

Преимуществом нисходящего подхода очень часто считают отсутствие необходимости в драйверах; вместо драйверов вам просто следует написать «заглушки».

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

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

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

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

Возникает вопрос: «Что лучше – выполнить по отдельности тестирование каждого модуля, а затем, комбинируя их, сформировать рабочую программу или же каждый модуль для тестирования подключать к набору ранее оттестированных модулей?». Первый подход обычно называют монолитным методом, или методом «большого удара», при тестировании и сборке программы; второй подход известен как пошаговый метод тестирования или сборки.

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

Детального разбора обоих методов мы делать не будем, приведем лишь некоторые общие выводы.

1.Монолитное тестирование требует больших затрат труда. При пошаговом же тестировании «снизу– вверх» затраты труда сокращаются.

2.Расход машинного времени при монолитном тестировании меньше.

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

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

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

6.Результаты пошагового тестирования более совершенны.

В заключение отметим, что п. 1, 4, 5, 6 демонстрируют преимущества пошагового тестирования, а п. 2 и 3 – его недостатки. Поскольку для современного этапа развития вычислительной техники характерны тенденции к уменьшению стоимости аппаратуры и увеличению стоимости труда, последствия ошибок в математическом обеспечении весьма серьезны, а стоимость устранения ошибки тем меньше, чем раньше она обнаружена; преимущества, указанные в п. 1, 4, 5, 6, выступают на первый план. В то же время ущерб, наносимый недостатками (п. 2 и 3), невелик. Все это позволяет нам сделать вывод, что пошаговое тестирование является предпочтительным.

Убедившись в преимуществах пошагового тестирования перед монолитным, исследуем две возможные стратегии тестирования: нисходящее и восходящее. Прежде всего внесем ясность в терминологию.

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

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

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

Тестирование разработчиком

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

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

Независимое тестирование

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

«Цель независимого тестирования — взглянуть на продукт с другой точки зрения, а следовательно, выполнить другие
тесты; таким образом, выполняется более разностороннее […] тестирование, чем если бы тестированием занимались
только разработчики». [BEI95]

Независимое тестирование заинтересованными лицами

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

Наконец, к этой категории независимого тестирования RUP относится понятие тестирования клиентами в терминологии
XP.

Тестирование модулей

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

Тестирование интеграции

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

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

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

Рекомендуется возложить ответственность за тестирование интеграции частично на разработчиков и частично на независимых
испытателей, при этом разработав стратегию, позволяющую минимизировать повторение одной и той же работы. Объем и
характер пересечения между тестами зависят от конкретного проекта. Мы рекомендуем применять подход, при котором
разработчики и независимые испытатели одинаково трактуют понятие качества. Дополнительные сведения приведены в разделе
Концепция: Тестирование разработчиками.

Тестирование системы

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

Приемка

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

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

Примечание о последовательности и времени выполнения разных уровней тестирования

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

Модульное тестирование (юнит-тестирование, unit testing) – это процесс в программировании, который позволяет проверить на корректность конкретные модули исходного кода.

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

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

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

Данный тип тестирования в основном выполняется программистами.

  • Модульное тестирование позволяет проводить рефакторинг, будучи уверенным, что модуль корректно работает.
  • Юнит-тестирование также помогает устранить сомнения по поводу отдельных модулей. Также может быть использован сначала для тестирования отдельных частей, а затем программы в целом.
  • Модульный тест можно рассматривать как «живой документ» для тестируемого класса.

Ограничения

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

Весь список терминов →

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

Модульное тестирование(Unit-testing) —
уровень тестирования, на котором
тестируется минимально возможный для
тестирования компонент, например,
отдельный класс или функция. На этом
уровне применяются методы «белого
ящика». В современных проектах модульное
тестирование («юнит-тестинг») осуществляется
разработчиками.

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

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

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

Интеграционное тестирование(Integration
testing) – уровень тестирования, на котором
отдельные программные модули объединяются
и тестируются в группе. Обычно
интеграционное тестирование проводится
после модульного тестирования (юнит-тесты
для модулей должны быть выполнены и
найденные ошибки исправлены).

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

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

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

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

Системное
тестирование
выполняется через внешние интерфейсы
программного обеспечения и тесно связано
с тестированием
пользовательского
интерфейса
(или через пользовательский интерфейс),
проводимым при помощи имитации действий
пользователей над элементами этого
интерфейса. Частными случаями этого
вида тестирования
являются тестирование
графического
пользовательского интерфейса
(Graphical User Interface, GUI) и пользовательского
интерфейса Web-приложений (WebUI).
Системное тестирование выполняется
инженерами по тестированию.

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

Рис.14. Уровни тестирования

Статическое
тестирование

(Static
testing)
– тестирование, в ходе которого
тестируемая программа (код) не выполняется
(запускается). Анализ программы происходит
на основе исходного кода, который
вычитывается вручную, либо анализируется
специальными инструментами.

Примеры статического
тестирования:

Обзоры
(Reviews)

Инспекции
(Inspections)

Сквозные
просмотры (Walkthroughs)

Аудиты
(Audits)

Также
к статическому тестированию относят
тестирование требований, спецификаций,
документации.

Динамическое
тестирование

(Dynamic
testing)–
тестирование, в ходе которого тестируемая
программа (код) выполняется (запускается).

Альфа-тестирование
тестирование в процессе разработки

Бета-тестирование— тестирование
выполняется пользователями (end-users)

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

Регрессионное
тестирование
(Regression
testing)
– тестирование функциональности,
которая была уже протестирована до
внесения какого-либо изменения.

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

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

Определение успешности регрессионных
тестов (IEEE 610-90 “Standard Glossary of Software
Engineering Terminology”) гласит: “повторное
выборочное тестирование системы или
компонент для проверки сделанных
модификаций не должно приводить к
непредусмотренным эффектам”. На практике
это означает, что если система успешно
проходила тесты до внесения модификаций,
она должна их проходить и после внесения
таковых. Основная проблема регрессионного
тестирования заключается в поиске
компромисса между имеющимися ресурсами
и необходимостью проведения таких
тестов по мере внесения каждого изменения.
В определенной степени, задача состоит
в том, чтобы определить критерии
“масштабов” изменений, с достижением
которых необходимо проводить регрессионные
тесты.

«Смок-тест»
(Smoke
Tes
ting,
«
дымовое
тестирование»)
в
тестировании означает минимальный
набор тестов на явные ошибки. Дымовой
тест обычно выполняется самим
программистом; не проходящую этот тест
программу не имеет смысла отдавать на
более глубокое тестирование.

***История.

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

Повторное «рождение»
термина произошло в радиоэлектронике.
Подключив в первый раз собранное
устройство к источнику питания,
радиолюбитель, пристально разглядывая
каждый участок печатной платы, проводит
так называемый «Smoke Test» — наблюдает,
задымится или нет, потому что очень
часто из-за досадных ошибок, допущенных
при монтаже схемы, она оказывалась
неработоспособна и отдельные её части
выходили из строя из-за перегрева (часто
с выделением дыма).

5.1.3
Виды тестирования

Функциональное тестирование(functional testing)

    • каждое функциональное требование
      транслируется в тест-кейсы (используя
      техники «черного ящика») для того,
      чтобы проверить, что система функционирует
      в точности, как и описано в спецификации
      (функциональных требованиях к системе)

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

Тестирование производительности(perfomance testing)

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

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

  • измерить, какая часть системы является
    причиной «плохой» производительности
    системы

  • измерить время реакции на действие
    пользователя, время отклика на запрос,
    и т.д.

Стрессовое тестирование (stress
testing)

  • тестирование операционных характеристик
    приложения в условиях ограниченных
    ресурсов (например, скорость, память,
    место на диске и т.д.)

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

Нагрузочное тестирование (load
testing)

  • применяется для анализа работы
    информационных систем на различных
    уровнях нагрузки.

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

  • определяем, при какой максимальной
    нагрузке (максимальном количестве
    пользователей) система способна
    функционирвать в соответствии с
    требованиями к производительности

  • HP LoadRunner

Тестирование удобства использования
(usability testing)


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


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

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

Процесс тестирования
фиксируется в протоколе (логе) и/или на
аудио- и видеоустройства — с целью
последующего более детального анализа.

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

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

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

  1. Речь модератора и респондента;

  2. Выражение лица респондента (снимается
    на видеокамеру);

  3. Изображение экрана компьютера, с которым
    работает респондент;

  4. Различные события, происходящие на
    компьютере, связанные с действиями
    пользователя:

  • Перемещение курсора и нажатия на
    клавиши мыши;

  • Использование клавиатуры;

  • Переходы между экранами (браузера или
    другой программы).

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

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

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

Тестирование интерфейса пользователя(UI testing)

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

    • проверяем, как приложение обрабатывает
      ввод с клавиатуры и «мышки» и как
      отображаются элементы графического
      интерфейса (текст, кнопки, меню, списки
      и прочие элементы).

Тестирование безопасности (security
testing)

— оценка уязвимости программного
обеспечения к различным атакам.

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

  • попытки узнать пароль с помощью внешних
    средств;

  • атака системы с помощью специальных
    утилит, анализирующих защиты;

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

  • целенаправленное введение ошибок в
    надежде проникнуть в систему в ходе
    восстановления;

  • просмотр несекретных данных в надежде
    найти ключ для входа в систему.

Тестирование локализации (localization
testing)

  • проверяем функционирует ли система
    как ожидается под разными языковыми
    локализациями операционных систем

Тестирование совместимости
(compatibility testing)

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

и др.

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]

  • #
  • #
  • #
  • #
  • #
  • #
  • #
  • #
  • #
  • #
  • #

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

Несколько слов о терминологии

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

Поэтому, если их код использует Ajax или localStorage, или IndexedDB и, следовательно, не может быть протестирован с помощью юнит-тестов, они оборачивают этот функционал в интерфейс и мокают этот интерфейс для юнит-тестов, а тестирование реальной реализации интерфейса называют «интеграционным тестом». С этой точки зрения «интеграционный тест» просто тестирует код, который взаимодействует с «реальным миром» вне тех юнитов, которые работают без учета реального мира.

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

Мое эмпирическое правило о том, следует ли использовать реальные реализации Ajax и других операций I/O (ввода-вывода) в интеграционных тестах, заключается в следующем: если вы можете это сделать и тесты все еще выполняются быстро и не ведут себя странно, то проверяйте I/O. Если операция I/O сложная, медленная или просто странная, то используйте в интеграционных тестах mock-объекты.

В нашем калькуляторе, к счастью, единственным реальным I/O является DOM. Нет вызовов Ajax и других причин писать «моки».

Фейковый DOM

Возникает вопрос: нужно ли писать фейковый DOM в интеграционных тестах? Применим моё правило. Использование реального DOM сделает тесты медленными? К сожалению, ответ — «да»: использование реального DOM означает использование реального браузера, что делает тесты медленными и непредсказуемыми.

Мы отделим большую часть кода от DOM или протестируем всё вместе в E2E-тестах? Оба варианта не оптимальны. К счастью, есть третье решение: jsdom . Этот замечательный и удивительный пакет делает именно то, чего от него ждёшь — реализует DOM в NodeJS.

Он работает, он быстр, он запускается в Node. Если вы используете этот инструмент, то можете перестать рассматривать DOM как «I/O». А это очень важно, ведь отделить DOM от фронтенд-кода сложно, если не невозможно. (Например, я не знаю, как сделать это.) Я предполагаю, что jsdom был написан именно для запуска фронтенд-тестов под Node.

Давайте посмотрим, как он работает. Как обычно, есть инициализирующий код и есть тестовый код, но на этот раз мы начнём с тестового. Но перед этим — отступление.

Отступление

Эта часть является единственной частью серии, которая ориентирована на конкретный фреймворк. И фреймворк, который я выбрал — это React. Не потому, что это лучший фреймворк. Я твердо верю, что нет такого понятия. Я даже не считаю, что существуют лучшие фреймворки для конкретных случаев использования. Единственное, во что я верю — люди должны использовать среду, в которой им наиболее комфортно работать.

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

Вернемся к использованию jsdom.

Использование jsdom

const React = require(«react»)
const e = React.createElement
const ReactDom = require(«react-dom»)
const CalculatorApp = require(«../../lib/calculator-app»)

describe(«calculator app component», function () {

it(«should work», function () {
ReactDom.render(e(CalculatorApp), document.getElementById(«container»))
const displayElement = document.querySelector(«.display»)
expect(displayElement.textContent).to.equal(«0»)

Интересными являются строки с 10 по 14. В строке 10 мы визуализируем компонент CalculatorApp , который (если вы следите за кодом в репозитории) также отображает компоненты Display и Keypad .

Затем мы проверяем, что в строках 12 и 14 элемент в DOM показывает на дисплее калькулятора начальное значение, равное 0.

И этот код, который работает под Node, использует document ! Глобальная переменная document является переменной браузера, но вот она здесь, в NodeJS. Чтобы эти строки работали, требуется очень большой объем кода. Этот очень большой объем кода, который находится в jsdom, является, по сути, полной реализацией всего, что есть в браузере, за вычетом самого рендеринга!

Строка 10, которая вызывает ReactDom для визуализации компонента, также использует document (и window), так как ReactDom часто использует их в своем коде.

Итак, кто создает эти глобальные переменные? Тест — давайте посмотрим на код:

Before(function () {
global.document = jsdom(`

`)
global.window = document.defaultView
})
after(function () {
delete global.window
delete global.document
})

В строке 3 мы создаём простой document , который содержит лишь div .

В строке 4 мы создаём глобальное window для объекта. Это нужно React.

Функция cleanup удалит эти глобальные переменные, и они не будут занимать память.

В идеале переменные document и window должны быть не глобальными. Иначе мы не сможем запустить тесты в параллельном режиме с другими интеграционными тестами, потому что все они будут переписывать глобальные переменные.

К сожалению, они должны быть глобальными — React и ReactDom нуждаются в том, чтобы document и window были именно такими, поскольку вы не можете им их передать.

Обработка событий

А как насчет остальной части теста? Давайте посмотрим:

ReactDom.render(e(CalculatorApp), document.getElementById(«container»))
const displayElement = document.querySelector(«.display»)
expect(displayElement.textContent).to.equal(«0»)
const digit4Element = document.querySelector(«.digit-4»)
const digit2Element = document.querySelector(«.digit-2»)
const operatorMultiply = document.querySelector(«.operator-multiply»)
const operatorEquals = document.querySelector(«.operator-equals»)
digit4Element.click()
digit2Element.click()
operatorMultiply.click()
digit2Element.click()
operatorEquals.click()
expect(displayElement.textContent).to.equal(«84»)

Остальная часть теста проверяет сценарий, в котором пользователь нажимает «42 * 2 =» и должен получить «84».

И он делает это красивым способом — получает элементы, используя известную функцию querySelector , а затем использует click , чтобы щелкнуть по ним. Вы даже можете создать событие и иницировать его вручную, используя что-то вроде:

Var ev = new Event(«keyup», …);
document.dispatchEvent(ev);

Но встроенный метод click работает, поэтому мы используем его.

Так просто!

Проницательный заметит, что этот тест проверяет точно то же самое, что и E2E-тест. Это правда, но обратите внимание, что этот тест примерно в 10 раз быстрее и является синхронным по своей природе. Его гораздо проще писать и гораздо легче читать.

А почему, если тесты одинаковы, нужен интеграционный? Ну, просто потому, что это учебный проект, а не настоящий. Два компонента составляют всё приложение, поэтому интеграционные и E2E-тесты делают одно и то же. Но в реальном приложении E2E-тест состоит из сотен модулей, тогда как интеграционные тесты включают в себя несколько, быть может, 10 модулей. Таким образом, в реальном приложении будет около 10 E2E-тестов, но сотни интеграционных тестов.

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

  • Блочное (Unit testing) — тестирование одного модуля в изоляции.
  • Интеграционное (Integration Testing) — тестирование группы взаимодействующих модулей.
  • Системное (System Testing) — тестирование системы в целом.

Классификация хорошая и понятная. Однако на практике выясняется, что у каждого вида тестирования есть свои особенности. И если их не учитывать, тестирование станивится обременительным и им не занимаются в должной мере. Здесь я собрал подходы к реальному применению различных видов тестирования. А поскольку я пишу на.NET, ссылки будут на соответствующие библиотеки.
Блочное (модульное, unit testing) тестирование наиболее понятное для программиста. Фактически это тестирование методов какого-то класса программы в изоляции от остальной программы.

Не всякий класс легко покрыть unit тестами. При проектировании нужно учитывать возможность тестируемости и зависимости класса делать явными. Чтобы гарантировать тестируемость можно применять TDD методологию , которая предписывает сначала писать тест, а потом код реализации тестируемого метода. Тогда архитектура получается тестируемой. Распутывание зависимостей можно осуществить с помощью Dependency Injection . Тогда каждой зависимости явно сопоставляется интерфейс и явно определяется как инжектируется зависимость — в конструктор, в свойство или в метод.

Для осуществления unit тестирования существуют специальные фреймворки. Например, NUnit или тестовый фреймфорк из Visual Studio 2008. Для возможности тестирования классов в изоляции существуют специальные Mock фреймворки. Например, Rhino Mocks . Они позволяют по интерфейсам автоматически создавать заглушки для классов-зависимостей, задавая у них требуемое поведение.

По unit тестированию написано много статей. Мне очень нравится MSDN статья Write Maintainable Unit Tests That Will Save You Time And Tears , в которой хорошо и понятно рассказывается как создавать тесты, поддерживать которые со временем не становится обременительно.

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

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

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

Хорошая статья по интеграционному тестированию мне попалась лишь однажды — Scenario Driven Tests . Прочтя ее и книгу Ayende по DSL DSLs in Boo, Domain-Specific Languages in .NET у меня появилась идея как все-таки устроить интеграционное тестирование.

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

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

1) Допустим в присланных документах есть несколько разделов. Тогда в спецификации мы можем указать, что у разбираемого документа должны быть разделы с указанными именами:

$SectionNames = Введение, Текст статьи, Заключение, Литература

2) Другой пример. При конвертировании нужно разбивать геометрические фигуры на примитивы. Разбиение считается удачным, если в сумме все примитивы полностью покрывают оригинальную фигуру. Из присланных документов выберем различные фигуры и для них напишем свои спецификации. Факт покрываемости фигуры примитивами можно отразить так:

$IsCoverable = true

Понятно, что для проверки подобных спецификаций потребуется движок, который бы считывал спецификации и проверял их соответствие поведению программы. Я такой движок написал и остался доволен данным подходом. Скоро выложу движок в Open Source. (UPD: Выложил)

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

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

Первый подход — это использовать вариацию MVC паттерна — Passive View (вот еще хорошая статья по вариациям MVC паттерна) и формализовать взаимодействие пользователя с GUI в коде. Тогда системное тестирование сводится к тестированию Presenter классов, а также логики переходов между View. Но тут есть нюанс. Если тестировать Presenter классы в контексте системного тестирования, то необходимо как можно меньше зависимостей подменять mock объектами. И тут появляется проблема инициализации и приведения программы в нужное для начала тестирования состояние. В упомянутой выше статье Scenario Driven Tests об этом говорится подробнее.

Второй подход — использовать специальные инструменты для записи действий пользователя. То есть в итоге запускается сама программа, но щелканье по кнопкам осуществляется автоматически. Для.NET примером такого инструмента является White библиотека . Поддерживаются WinForms, WPF и еще несколько GUI платформ. Правило такое — на каждый use case пишется по скрипту, который описывает действия пользователя. Если все use case покрыты и тесты проходят, то можно сдавать систему заказчику. Акт сдачи-приемки должен подписать.

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

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

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

Интеграционное тестирование применяется на этапе сборки модульно оттестированных модулей в единый комплекс. Известны два метода сборки модулей:
Монолитный
, характеризующийся одновременным объединением всех модулей в тестируемый комплекс
Инкрементальный
, характеризующийся пошаговым (помодульным) наращиванием комплекса программ с пошаговым тестированием собираемого комплекса. В инкрементальном методе выделяют две стратегии добавления модулей:
o «Сверху вниз» и соответствующее ему восходящее тестирование.
o «Снизу вверх» и соответственно нисходящее тестирование.

Особенности монолитного тестирования
заключаются в следующем: для замены неразработанных к моменту тестирования модулей, кроме самого верхнего, необходимо дополнительно разрабатывать драйверы (test driver) и/или заглушки (stub), замещающие отсутствующие на момент сеанса тестирования модули нижних уровней.

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

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

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

Недостатки восходящего тестирования
:
Запаздывание проверки концептуальных особенностей тестируемого комплекса
Необходимость в разработке и использовании драйверов

Особенности интеграционного тестирования для процедурного программирования

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

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

100 р
бонус за первый заказ

Выберите тип работы
Дипломная работа
Курсовая работа
Реферат
Магистерская диссертация
Отчёт по практике
Статья
Доклад
Рецензия
Контрольная работа
Монография
Решение задач
Бизнес-план
Ответы на вопросы
Творческая работа
Эссе
Чертёж
Сочинения
Перевод
Презентации
Набор текста
Другое
Повышение уникальности
текста
Кандидатская диссертация
Лабораторная работа
Помощь on-line

Узнать цену

В статье третьей (УШ № 32) говорилось о традиционных тестах. Там же приводились определения гомогенных и гетерогенных тестов. В сегодняшней статье — материал о нетрадиционных тестах, к которым можно отнести тесты интегративные, адаптивные, многоступенчатые и так называемые критериально-ориентированные тесты.

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

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

Методика создания интегративных тестов сходна с методикой создания традиционных тестов, за исключением работы по определению содержания заданий. Для отбора содержания интегративных тестов использование экспертных методов является обязательным. Это связано с тем, что только эксперты могут определить адекватность содержания заданий целям теста. Но, прежде всего, самим экспертам важно будет определиться с целями образования и изучения тех или иных образовательных программ, а затем и договориться между собой по принципиальным вопросам, оставив для экспертизы лишь вариации в понимании степени значимости отдельных элементов в общей структуре подготовленности. Согласованный, по принципиальным вопросам, отобранный состав экспертов в зарубежной литературе нередко панелью. Или учитывая различия в смысле последнего слова, в русском языке, такой состав можно назвать представительной экспертной группой. Группа подбирается так, чтобы адекватно представлять подход, используемый при создании соответствующего теста.

Интеграционное тестирование редко попадает в заголовки статей из раздела «Информационные технологии». Масштаб ошибок интеграции не сравнится по степени критичности и по размеру понесенных убытков с ошибками безопасности.

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

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

Что же это за тестирование и как оно проводится?

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

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

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

Интеграционное тестирование: обзор проекта

Заказчик

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

Задача проекта

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

Для реализации функции подписки и ее управления заказчик использовал следующие программные решения:

  • CMS-решение eZ Publish. Функция – предоставлять любые данные о подписках с применением различных фильтров: типа подписки, ее продолжительности, применяемых скидок, бонусов и так далее.
  • Вебсайт, через который пользователь взаимодействует с системой.
  • CRM Salesforce. Функция – хранение данных о пользователях и приобретенных ими подписках. Дополнительная надстройка позволяет команде заказчика управлять приобретенными подписками, а также создавать новые и проверять старые подписки.
  • SaaS-решение Zuora для выставления счетов и обработки платежей.
  • Обмен данными между системами осуществляется с помощью сервисной шины Mule ESB.
  • База данных как инструмент Business Intelligence.
  • Salesforce Marketing Cloud – инструмент рассылки корреспонденции и коммуникации с пользователями.
  • Drupal ранее использовался вместо eZ Publish. На данный момент все еще остается системой, хранящей данные о зарегистрированных пользователях, и инструментом для публикации статей, видео- и аудио-контента.

Процесс оформления подписки был построен следующим образом:

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

Цель клиента

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

Задача тестирования

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

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

Стратегия проведения интеграционного тестирования a1qa

  1. Определены ключевые бизнес-процессы, которые должна выполнять система: создание, отмена, приостановка и возобновление подписки, изменение платежной информации для подписки и т.д.
  2. Разработана тестовая документация с учетом всех возможных вариаций. Вариации – различные альтернативные выполнения операций (например, отмена подписки может произойти по желанию заказчика, а может быть произведена автоматически, если платежные данные были отклонены банком), а также различные параметры (например, тип продукта). В документации требовалось учесть проверку того, например, что создание подписки пройдет успешно для всех продуктов в рамках каждого бизнес-процесса.
  3. Проведение тестирования, которое заключалось в пошаговом прохождении каждого бизнес-процесса со стартового компонента (где он был инициирован) через все промежуточные и до финального (или финальных) с проверкой того, что все данные передаются правильно, а ожидаемые события на самом деле случаются.

Большинство процессов включало в себя передачу данных из одного модуля (чаще всего из Salesforce) во все остальные. Если начальной точкой был не SF, то информация из модуля поступала в MuleESB, а потом в SF, а оттуда во все остальные (опять же, через MuleESB).

На проведение тестирования интеграции было потрачено порядка 40% всех трудозатрат QA-команды.

Трудности

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

Поясним. Изначально требования выглядели как набор пользовательских историй (User Story) в JIRA и содержали только заголовки без какого-либо пояснения. Создавали их чаще всего разработчики.

Команда a1qa инициировала изменения в подходе написания требований: теперь для них обязательно добавляются описания и Acceptance Criteria, создаются промежуточные задачи с четким определением, кто и за что отвечает.

Автоматизация интеграционного тестирования

Автоматизация тестирования – непростой вопрос, который требует внимательного сопоставления всех «за» и «против».

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

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

Результаты

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

Подводя итоги

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

Для проведения эффективного тестирования, обнаружения всех дефектов и недочетов команда по тестированию должна:

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

Как заказать интеграционное тестирование?

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