Виды Тестирования ПО. Полный Список. Методология и практика тестирования по

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

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

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

Тестирование ПО — попытка определить, выполняет ли программа то, что от неё ожидают. Как правило, никакое тестирование не может дать абсолютной гарантии работоспособности программы в будущем.

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

Например: Корпорация Microsoft выпускает пакеты обновлений («Service Pack»), для своих операционных систем. Разработчики игр регулярно выпускают «патчи» для своих продуктов. Большинство разработчиков ПО после устранения ошибок выпускают обновлённую (новую) версию своей программы.

Тестирование программного обеспечения

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

По объекту тестирования:

  • Функциональное тестирование (functional testing)
  • Нагрузочное тестирование
    • Тестирование производительности (perfomance/stress testing)
    • Тестирование стабильности (stability/load testing)
  • Тестирование удобства использования (usability testing)
  • Тестирование интерфейса пользователя (UI testing)
  • Тестирование безопасности (security testing)
  • Тестирование локализации (localization testing)
  • Тестирование совместимости (compatibility testing)

По знанию системы:

  • Тестирование чёрного ящика (black box)
  • Тестирование белого ящика (white box)
  • Тестирование серого ящика (gray box)

По степени автоматизированности:

  • Ручное тестирование (manual testing)
  • Автоматизированное тестирование (automated testing)
  • Полуавтоматизированное тестирование (semiautomated testing)

По степени изолированности компонентов:

  • Компонентное (модульное) тестирование (component/unit testing)
  • Интеграционное тестирование (integration testing)
  • Системное тестирование (system/end-to-end testing)

По времени проведения тестирования:

  • Альфа тестирование (alpha testing)
    • Тестирование при приёмке (smoke testing)
    • Тестирование новых функциональностей (new feature testing)
    • Регрессионное тестирование (regression testing)
    • Тестирование при сдаче (acceptance testing)
  • Бета тестирование (beta testing)

По признаку позитивности сценариев:

  • Позитивное тестирование (positive testing)
  • Негативное тестирование (negative testing)

По степени подготовленности к тестированию:

  • Тестирование по документации (formal testing)
  • Эд Хок (интуитивное) тестирование (ad hoc testing)

Уровни тестирования

  • Модульное тестирование (юнит-тестирование) — тестируется минимально возможный для тестирования компонент, например, отдельный класс или функция. Часто модульное тестирование осуществляется разработчиками ПО.
  • Интеграционное тестирование — тестируются интерфейсы между компонентами, подсистемами. При наличии резерва времени на данной стадии тестирование ведётся итерационно, с постепенным подключением последующих подсистем.
  • Системное тестирование — тестируется интегрированная система на её соответствие требованиям.
    • Альфа-тестирование — имитация реальной работы с системой штатными разработчиками, либо реальная работа с системой потенциальными пользователями/заказчиком. Чаще всего альфа-тестирование проводится на ранней стадии разработки продукта, но в некоторых случаях может применяться для законченного продукта в качестве внутреннего приёмочного тестирования. Иногда альфа-тестирование выполняется под отладчиком или с использованием окружения, которое помогает быстро выявлять найденные ошибки. Обнаруженные ошибки могут быть переданы тестировщикам для дополнительного исследования в окружении, подобном тому, в котором будет использоваться ПО.
    • Бета-тестирование — в некоторых случаях выполняется распространение версии с ограничениями (по функциональности или времени работы) для некоторой группы лиц, с тем чтобы убедиться, что продукт содержит достаточно мало ошибок. Иногда бета-тестирование выполняется для того, чтобы получить обратную связь о продукте от его будущих пользователей.

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

Тестирование «белого ящика» и «чёрного ящика»

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

При тестировании белого ящика (англ. white-box testing , также говорят — прозрачного ящика ), разработчик теста имеет доступ к исходному коду программ и может писать код, который связан с библиотеками тестируемого ПО. Это типично для юнит-тестирования (англ. unit testing ), при котором тестируются только отдельные части системы. Оно обеспечивает то, что компоненты конструкции — работоспособны и устойчивы, до определённой степени. При тестировании белого ящика используются метрики покрытия кода.

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

Если «альфа-» и «бета-тестирование» относятся к стадиям до выпуска продукта (а также, неявно, к объёму тестирующего сообщества и ограничениям на методы тестирования), тестирование «белого ящика» и «чёрного ящика» имеет отношение к способам, которыми тестировщик достигает цели.

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

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

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

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

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

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

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

Тестовые скрипты

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

Покрытие кода

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

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

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

Разработка через тестирование (test-driven development)

(англ. test-driven development) — техника программирования, при которой модульные тесты для программы или её фрагмента пишутся до самой программы (англ. test-first development) и, по существу, управляют её разработкой. Является одной из основных практик экстремального программирования.

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

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

Методика разработки через тестирование(Test-Driven Development, TDD) позволяет получить ответы на вопросы об организации автоматических тестов и выработке определенных навыков тестирования.

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

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

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

    Разработчику приятнее писать такой код.

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

    Пишем новый код только тогда, когда автоматический код не сработал.

    Удаляем дублирование.

Два столь простых правила на самом деле генерируют сложное индивидуальное и групповое поведение со множеством технических последствий:

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

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

    Наша среда разработки должна быстро реагировать на небольшие модификации кода.

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

Два упомянутых правила TDD определяют порядок этапов программирования:

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

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

    Рефакторинг - удалите из написанного вами кода любое дублирование.

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

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

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

Терминология, связанная с модульными тестами

  • Разработка через тестирование - процесс разработки программного обеспечения, который предусматривает написание и автоматизацию модульных тестов еще до момента написания соответствующих классов или модулей. Это гарантирует, что все обязанности любого элемента программного обеспечения определяются еще до того, как они будут закодированы.
  • Модульные тесты - Unit Tests, Programming Tests, Developer Tests - тесты, проверяющие функциональность отдельных классов, компонентов, модулей приложения. Эти тесты не видны конечному заказчику или доменному эксперту. Обычно их начинают писать после оформления функциональных тестов.
  • Зеленая/Красная полоса - многие графические среды для выполнения модульных тестов отображают результат выполнения тестов в виде линии, которая окрашена в зеленый цвет, если все тесты выполнились удачно, и красной, если были ошибки.
  • Моки, Мок-объекты (MockObjects) - автоматически генерируемые заглушки, которые могу выступат в роли реальных объектов. Поведением моков можно управлять непосредственно в тесте. Моки могут выполнять дополнительные проверки, что тестируемый код их использовал, как ожидалось.
  • Модульный тест - тест, который проверяет поведение небольшой части приложения. Эта часть может быть одним классом, одним методом или набором классов, который реализуют какое-то архитектурное решение, и это решение необходимо проверить на работоспособность.
  • Тест - TestCase - набор тестовых методов, предназначенных для тестирования одного класса (в среде xUnit). Обычно TestCase состоит из методов, чье имя начинается с приставки test. Каждый такой метод тестирует какой-либо один момент тестируемого класса. В приемочном тестировании TestCase - это набор команд, которые тестируют одну значимую для заказчика функциональность.
  • Фикстура - Fixture - состояние среды тестирования, которое требуется для успешного выполнения тестового метода. Это может быть набор каких-либо объектов, состояние базы данных, наличие определенных файлов и т.д. Фикстура создается в методе setUp() перед каждым вызовом метода вида testSomething теста (TestCase) и удаляется в tearDown() после окончания выполнения тестового метода.
  • Проверка - Assert - метод класса TestCase, который предназначен для сверки реального состояния тестируемого кода с ожидаемым.

Терминология, связанная с наборами тестов

  • Набор тестов - TestSuite - набор тестов, предназначенный для тестирования какой-либо укрупненной сущности программной системы. В SimpleTest есть понятие TestGroup, которые практически эквивалентно понятию TestSuite. Иногда TestSuite употребляют в значении «все тесты, которые есть для приложения».

Терминология, связанная с приемочными тестами

  • Приемочные (функциональные) тесты - Customer tests, Acceptance tests - тесты, проверяющие функциональность приложения на соответствие требованиям заказчика. Приемочные тесты не должны ничего знать о деталях реализации приложения. Приемочные тесты заменяют ТЗ при использовании методики экстремального программирования (XP).
  • Регрессионный тесты - тесты, которые проверяют, что поведение системы не изменилось. На самом деле, большинство регрессионных тестов являются или модульными или функциональными тестами, которые включаются в определенный набор тестов (RegressionTestSuite), который гарантирует, что функциональность системы не будет случайно изменена.

— процесс исследования программного обеспечения (ПО) с целью получения информации о качестве продукта.

Введение

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

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

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

С точки зрения ISO 9126, Качество (программных средств) можно определить как совокупную характеристику исследуемого ПО с учётом следующих составляющих:

· Надёжность

· Сопровождаемость

· Практичность

· Эффективность

· Мобильность

· Функциональность

Более полный список атрибутов и критериев можно найти в стандарте ISO 9126 Международной организации по стандартизации. Состав и содержание документации, сопутствующей процессу тестирования, определяется стандартом IEEE 829-1998 Standard for Software Test Documentation.

Тестирование программного обеспечения

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

По объекту тестирования:

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

· Нагрузочное тестирование

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

· Тестирование стабильности (stability/load testing)

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

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

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

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

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

По знанию системы:

· Тестирование чёрного ящика (black box)

· Тестирование белого ящика (white box)

· Тестирование серого ящика (gray box)

По степени автоматизированности:

· Ручное тестирование (manual testing)

· Автоматизированное тестирование (automated testing)

· Полуавтоматизированное тестирование (semiautomated testing)

По степени изолированности компонентов:

· Компонентное (модульное) тестирование (component/unit testing)

· Интеграционное тестирование (integration testing)

· Системное тестирование (system/end-to-end testing)

По времени проведения тестирования:

· Альфа тестирование (alpha testing)

· Тестирование при приёмке (smoke testing)

· Тестирование новых функциональностей (new feature testing)

· Регрессионное тестирование (regression testing)

· Тестирование при сдаче (acceptance testing)

· Бета тестирование (beta testing)

По признаку позитивности сценариев:

· Позитивное тестирование (positive testing)

· Негативное тестирование (negative testing)

По степени подготовленности к тестированию:

· Тестирование по документации (formal testing)

· Эд Хок (интуитивное) тестирование (ad hoc testing)

Уровни тестирования

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

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

Системное тестирование — тестируется интегрированная система на её соответствие требованиям.

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

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

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

Тестирование «белого ящика» и «чёрного ящика»

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

При тестировании белого ящика (англ. white-box testing, также говорят — прозрачного ящика), разработчик теста имеет доступ к исходному коду программ и может писать код, который связан с библиотеками тестируемого ПО. Это типично для юнит-тестирования (англ. unit testing), при котором тестируются только отдельные части системы. Оно обеспечивает то, что компоненты конструкции — работоспособны и устойчивы, до определённой степени. При тестировании белого ящика используются метрики покрытия кода.

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

Если «альфа-» и «бета-тестирование» относятся к стадиям до выпуска продукта (а также, неявно, к объёму тестирующего сообщества и ограничениям на методы тестирования), тестирование «белого ящика» и «чёрного ящика» имеет отношение к способам, которыми тестировщик достигает цели.

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

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

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

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

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

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

Регрессио́нное тести́рование (англ. regression testing, от лат. regressio — движение назад) — собирательное название для всех видов тестирования программного обеспечения, направленных на обнаружение ошибок в уже протестированных участках исходного кода. Такие ошибки — когда после внесения изменений в программу перестает работать то, что должно было продолжать работать, — называют регрессионными ошибками (англ. regression bugs).

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

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

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

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

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

Цитата

«Фундаментальная проблема при сопровождении программ состоит в том, что исправление одной ошибки с большой вероятностью (20-50%) влечет появление новой. Поэтому весь процесс идет по принципу "два шага вперед, шаг назад".

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

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

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

Тестовые скрипты

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

Покрытие кода

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

Критерии

Существует несколько различных способов измерения покрытия, основные из них:

· Покрытие операторов — каждая ли строка исходного кода была выполнена и протестирована?

· Покрытие условий — каждая ли точка решения (вычисления истинно ли или ложно выражение) была выполнена и протестирована?

· Покрытие путей — все ли возможные пути через заданную часть кода были выполнены и протестированы?

· Покрытие функций — каждая ли функция программы была выполнена

· Покрытие вход/выход — все ли вызовы функций и возвраты из них были выполнены

Для программ с особыми требованиями к безопасности часто требуется продемонстрировать, что тестами достигается 100 % покрытие для одного из критериев. Некоторые из приведённых критериев покрытия связаны между собой; например, покрытие путей включает в себя и покрытие условий и покрытие операторов. Покрытие операторов не включает покрытие условий, как показывает этот код на Си:

printf("this is ");

if (bar < 1)

printf("not ");

printf (" a positive integer ");

Если здесь bar = −1, то покрытие операторов будет полным, а покрытие условий — нет, так как случай несоблюдения условия в операторе if — не покрыт. Полное покрытие путей обычно невозможно. Фрагмент кода, имеющий n условий содержит 2n путей; конструкция цикла порождает бесконечное количество путей. Некоторые пути в программе могут быть не достигнуты из-за того, что в тестовых данных отсутствовали такие, которые могли привести к выполнению этих путей. Не существует универсального алгоритма, который решал бы проблему недостижимых путей (этот алгоритм можно было бы использовать для решения проблемы останова). На практике для достижения покрытия путей используется следующий подход: выделяются классы путей (например, к одному классу можно отнести пути отличающиеся только количеством итераций в одном и том же цикле), 100 % покрытие достигнуто, если покрыты все классы путей (класс считается покрытым, если покрыт хотя бы один путь из него).

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

Практическое применение

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

Степень покрытия кода обычно выражают в виде процента. Например, «мы протестировали 67 % кода». Смысл этой фразы зависит от того какой критерий был использован. Например, 67 % покрытия путей — это лучший результат чем 67 % покрытия операторов. Вопрос о связи значения покрытия кода и качеством тестового набора ещё до конца не решён.

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

Как правило, инструменты и библиотеки, используемые для получения покрытия кода, требуют значительных затрат производительности и/или памяти, недопустимых при нормальном функционировании ПО. Поэтому они могут использоваться только в лабораторных условиях. E-mail: [email protected]

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

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

Что такое тестирование программного обеспечения?

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

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

Методика тестирования

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

3) Системное тестирование

4) Приемочные испытания

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


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

Системное тестирование

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

Приемочные испытания

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

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

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

Тестирование методом черного ящика

Тестирование методом черного ящика осуществляется без каких-либо знаний внутренней работы системы. Тестер будет стимулировать программное обеспечение для пользовательской среды, предоставляя различные входы и тестируя сгенерированные выходы. Этот тест также известен как Black-box, closed-box тестирование или функциональное тестирование.

Тестирование методом белого ящика

Тестирование методом "Белого ящика", в отличие от "черного ящика", учитывает внутреннее функционирование и логику работы кода. Для выполнения этого теста, тестер должен иметь знания кода, чтобы узнать точную часть кода, имеющую ошибки. Этот тест также известен как White-box, Open-Box или Glass box тестирование.

Тестирование методом серого ящика

Тестирование методом серого ящика или Gray box тестирование, это что-то среднее между White Box и Black Box тестированием, где тестер обладает лишь общими знаниями данного продукта, необходимыми для выполнения теста. Эта проверка осуществляется посредством документации и схемы информационных потоков. Тестирование проводится конечным пользователем, или пользователям, которые представляются как конечные.

Нефункциональные тесты

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

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


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


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

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

Тесты в процессе разработки программного обеспечения

Каскадная модель использует подход "сверху-вниз", независимо от того, используется ли она для разработки программного обеспечения или для тестирования.

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

  • Анализ потребностей
  • Тест дизайна
  • Тест реализации
  • Тестирование, отладка и проверка кода или продукта
  • Внедрение и обслуживание

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

Agile Model

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

Rapid Application Development (RAD). Методология быстрой разработки приложений

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

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

Спиральная модель

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

Rational Unified Process (RUP). Рациональный унифицированный процесс

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

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

Введение

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

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

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

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

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

Основная статья: Регрессионное тестирование

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

Тестовые скрипты

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

Тестирование «белого ящика» и «чёрного ящика»

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

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

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

Если «альфа-» и «бета-тестирование» относятся к стадиям до выпуска продукта (а также, неявно, к объёму тестирующего сообщества и ограничениям на методы тестирования), тестирование «белого ящика» и «чёрного ящика» имеет отношение к способам, которыми тестировщик достигает цели.

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

Покрытие кода

Основная статья: Покрытие кода

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

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

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

Цитаты

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

См. также

  • Обратная семантическая трассировка - универсальный метод тестирования любого проектного артефакта

Примечания

Литература

  • Гленфорд Майерс, Том Баджетт, Кори Сандлер Искусство тестирования программ, 3-е издание = The Art of Software Testing, 3rd Edition. - М .: «Диалектика», 2012. - 272 с. - ISBN 978-5-8459-1796-6
  • Лайза Криспин, Джанет Грегори Гибкое тестирование: практическое руководство для тестировщиков ПО и гибких команд = Agile Testing: A Practical Guide for Testers and Agile Teams. - М .: «Вильямс», 2010. - 464 с. - (Addison-Wesley Signature Series). - 1000 экз. - ISBN 978-5-8459-1625-9
  • Канер Кем, Фолк Джек, Нгуен Енг Кек Тестирование программного обеспечения. Фундаментальные концепции менеджмента бизнес-приложений. - Киев: ДиаСофт, 2001. - 544 с. - ISBN 9667393879
  • Калбертсон Роберт, Браун Крис, Кобб Гэри Быстрое тестирование. - М .: «Вильямс», 2002. - 374 с. - ISBN 5-8459-0336-X
  • Синицын С. В., Налютин Н. Ю. Верификация программного обеспечения. - М .: БИНОМ, 2008. - 368 с. - ISBN 978-5-94774-825-3
  • Бейзер Б. Тестирование чёрного ящика. Технологии функционального тестирования программного обеспечения и систем. - СПб. : Питер, 2004. - 320 с. - ISBN 5-94723-698-2

Ссылки

  • Портал специалистов по тестированию и обеспечению качества ПО (рус.)
  • Портал об автоматизированном тестировании ПО (рус.)
  • Качество программного обеспечения (рус.)

Тестирование программного обеспечения - процесс исследования программного обеспечения (ПО) с целью получения информации о качестве продукта.

Введение

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

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

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

С точки зрения ISO 9126, Качество (программных средств) можно определить как совокупную характеристику исследуемого ПО с учётом следующих составляющих:

· Надёжность

· Сопровождаемость

· Практичность

· Эффективность

· Мобильность

· Функциональность

Более полный список атрибутов и критериев можно найти в стандарте ISO 9126 Международной организации по стандартизации. Состав и содержание документации, сопутствующей процессу тестирования, определяется стандартом IEEE 829-1998 Standard for Software Test Documentation.

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

Тестирование программного обеспечения

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

По объекту тестирования:

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

· Нагрузочное тестирование

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

· Тестирование стабильности (stability/load testing)

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

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

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

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

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

По знанию системы:

· Тестирование чёрного ящика (black box)

· Тестирование белого ящика (white box)

· Тестирование серого ящика (gray box)

По степени автоматизированности:

· Ручное тестирование (manual testing)

· Автоматизированное тестирование (automated testing)

· Полуавтоматизированное тестирование (semiautomated testing)

По степени изолированности компонентов:

· Компонентное (модульное) тестирование (component/unit testing)

· Интеграционное тестирование (integration testing)

· Системное тестирование (system/end-to-end testing)

По времени проведения тестирования:

· Альфа тестирование (alpha testing)

· Тестирование при приёмке (smoke testing)

· Тестирование новых функциональностей (new feature testing)

· Регрессионное тестирование (regression testing)

· Тестирование при сдаче (acceptance testing)

· Бета тестирование (beta testing)

По признаку позитивности сценариев:

· Позитивное тестирование (positive testing)

· Негативное тестирование (negative testing)

По степени подготовленности к тестированию:

· Тестирование по документации (formal testing)

· Эд Хок (интуитивное) тестирование (ad hoc testing)

Уровни тестирования

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

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

Системное тестирование - тестируется интегрированная система на её соответствие требованиям.

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

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

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

Тестирование «белого ящика» и «чёрного ящика»

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

При тестировании белого ящика (англ. white-box testing, также говорят - прозрачного ящика), разработчик теста имеет доступ к исходному коду программ и может писать код, который связан с библиотеками тестируемого ПО. Это типично для юнит-тестирования (англ. unit testing), при котором тестируются только отдельные части системы. Оно обеспечивает то, что компоненты конструкции - работоспособны и устойчивы, до определённой степени. При тестировании белого ящика используются метрики покрытия кода.

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

Если «альфа-» и «бета-тестирование» относятся к стадиям до выпуска продукта (а также, неявно, к объёму тестирующего сообщества и ограничениям на методы тестирования), тестирование «белого ящика» и «чёрного ящика» имеет отношение к способам, которыми тестировщик достигает цели.

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

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

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

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

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

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

Регрессио́нное тести́рование (англ. regression testing, от лат. regressio - движение назад) - собирательное название для всех видов тестирования программного обеспечения, направленных на обнаружение ошибок в уже протестированных участках исходного кода. Такие ошибки - когда после внесения изменений в программу перестает работать то, что должно было продолжать работать, - называют регрессионными ошибками (англ. regression bugs).

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

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

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

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

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

«Фундаментальная проблема при сопровождении программ состоит в том, что исправление одной ошибки с большой вероятностью (20-50%) влечет появление новой. Поэтому весь процесс идет по принципу "два шага вперед, шаг назад".

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

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

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

Тестовые скрипты

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

Покрытие кода

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

Критерии

Существует несколько различных способов измерения покрытия, основные из них:

· Покрытие операторов - каждая ли строка исходного кода была выполнена и протестирована?

· Покрытие условий - каждая ли точка решения (вычисления истинно ли или ложно выражение) была выполнена и протестирована?

· Покрытие путей - все ли возможные пути через заданную часть кода были выполнены и протестированы?

· Покрытие функций - каждая ли функция программы была выполнена

· Покрытие вход/выход - все ли вызовы функций и возвраты из них были выполнены

Для программ с особыми требованиями к безопасности часто требуется продемонстрировать, что тестами достигается 100 % покрытие для одного из критериев. Некоторые из приведённых критериев покрытия связаны между собой; например, покрытие путей включает в себя и покрытие условий и покрытие операторов. Покрытие операторов не включает покрытие условий, как показывает этот код на Си:

printf("this is ");

printf("a positive integer");

Если здесь bar = −1, то покрытие операторов будет полным, а покрытие условий - нет, так как случай несоблюдения условия в операторе if - не покрыт. Полное покрытие путей обычно невозможно. Фрагмент кода, имеющий n условий содержит 2n путей; конструкция цикла порождает бесконечное количество путей. Некоторые пути в программе могут быть не достигнуты из-за того, что в тестовых данных отсутствовали такие, которые могли привести к выполнению этих путей. Не существует универсального алгоритма, который решал бы проблему недостижимых путей (этот алгоритм можно было бы использовать для решения проблемы останова). На практике для достижения покрытия путей используется следующий подход: выделяются классы путей (например, к одному классу можно отнести пути отличающиеся только количеством итераций в одном и том же цикле), 100 % покрытие достигнуто, если покрыты все классы путей (класс считается покрытым, если покрыт хотя бы один путь из него).

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

Практическое применение

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

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

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

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

Введение

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

Когда вам скажут, что жизненный цикл продукта состоит из проектирования, реализации, тестирования и поддержки - не верьте! Тестирование сопровождает проект всю его жизнь - от момента рождения до самой смерти. Проектировщик закладывает механизмы самодиагностики и вывода "телеметрической" информации. Разработчик тестирует каждую запрограммированную им функцию (тестирование на микроуровне). Бета-тестеры проверяют работоспособность всего продукта в целом. У каждого из них должен быть четкий план действий, в противном случае тестирование провалится, еще не начавшись.

В идеале для каждой функции исходного кода разрабатывается набор автоматизированных тестов, предназначенных для проверки ее работоспособности. Лучше всего поручить эту работу отдельной группе программистов, поставив перед ними задачу: разработать такой пример, на котором функция провалится. Вот, например, функция сортировки. Простейший тест выглядит так. Генерируем произвольные данные, прогоняем через нее и если для каждого элемента N условие N <= N + 1 (N >= N + 1 для сортировки по убыванию) истинно, считаем, что тест пройдет правильно. Но ведь этот тест неправильный! Необходимо убедиться, что на выходе функции присутствуют все исходные данные и нет ничего лишнего! Многие функции нормально сортируют десять или даже тысячу элементов, но спотыкаются на одном или двух (обычно это происходит при сортировке методом деления напополам). А если будет ноль сортируемых элементов? А если одна из вызываемых функций (например, malloc), возвратит ошибку - сможет ли тестируемая функция корректно ее обработать? Сколько времени (системных ресурсов) потребуется на сортировку максимально возможного числа элементов? Неоправданно низкая производительность - тоже ошибка!

Существует два основных подхода к тестированию - черный и белый ящики. "Черный ящик" - это функция с закрытым кодом, проверка которого сводится к тупому перебору всех комбинаций аргументов. Очевидно, что подавляющее большинство функций не могут быть протестированы за разумное время (количество комбинаций слишком велико). Код белого ящика известен и тестировщик может сосредоточить свое внимание на пограничных областях. Допустим, в функции есть ограничение на предельно допустимую длину строки в MAX_LEN символов. Тогда следует тщательно исследовать строки в MAX_LEN - 1, MAX_LEN и MAX_LEN + 1 символов, поскольку ошибка "в плюс-минус один байт" - одна из самых популярных.

Тест должен задействовать все ветви программы, чтобы после его выполнения не осталось ни одной незадействованной строчки кода. Соотношение кода, который хотя бы раз получил выполнение, к общему коду программы, называется покрытием (coverage) и для его измерения придумано множество инструментов - от профилировщиков, входящих в штатный комплект поставки компиляторов, до самостоятельных пакетов, лучшим из которых является NuMega True Coverage.

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

Всегда транслируйте программу с максимальным уровнем предупреждений (для Microsoft Visual C++ это ключ /W4), обращая внимание на все сообщения компилятора. Некоторые, наиболее очевидные ошибки обнаруживаются уже на этом этапе. Сторонние верификаторы кода (lint, smatch) еще мощнее и распознают ошибки, с которыми трансляторы уже не справляются.

Регистрация ошибок

Завалить программу - проще всего. Зафиксировать обстоятельства сбоя намного сложнее. Типичная ситуация: тестировщик прогоняет программу через серию тестов. Непройденные тесты отправляются разработчику, чтобы тот локализовал ошибку и исправил баги. Но у разработчика эти же самые тесты проходят успешно! А, он уже все переделал, перекомпилировал с другими ключами и т.д. Чтобы этого не происходило, используйте системы управления версиями - Microsoft Source Safe или никсовый CVS.

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

Самыми коварными являются "плавающие" ошибки, проявляющиеся с той или иной степенью вероятности - девятьсот прогонов программа проходит нормально, а затем неожиданно падает без всяких видимых причин. Эй, кто там орет, что такого не бывает? Машина, дескать, детерминирована, и если железо исправно, то баг либо есть, либо нет. Ага, разбежались! Многопоточные приложения и код, управляющий устройствами ввода/вывода, порождают особый класс невоспроизводимых ошибок, некоторые из которых могут проявляться лишь раз в несколько лет! Вот типичный пример:

f1() {int x = strlen(s); s[x] = "*"; s = 0;} // поток 1

f2() {printf("%s\n", s);} // поток 2

Листинг 1. Пример плавающей ошибки.

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

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

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

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

Бета-тестирование

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

Уронив программу (или добившись от нее выдачи неверных данных), бета-тестер должен суметь воспроизвести сбой, т.е. выявить наиболее короткую последовательность операций, приводящую к ошибке. А сделать это ой как непросто! Попробуй-ка вспомнить, какие клавиши были нажаты! Что? Не получается?! Су... Используйте клавиатурные шпионы. На любом хакерском сайте их навалом. Пусть поработают на благо народа (не вечно же пароли похищать). Шпионить за мышью намного сложнее - приходится сохранять не только позицию курсора, но координаты всех окон или задействовать встроенные макросредства (по типу Visual Basic"a в Word"е). В общем, мышь - это саксь и маст дай. Нормальные бета-тестеры обходятся одной клавиатурой. Полный протокол нажатий сокращает круг поиска ошибки, однако с первого раза воспроизвести сбой удается не всегда и не всем.

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

Тестируйте программу на всей линейке операционных систем: Windows 98, Windows 2000, Windows 2003 и т.д. Различия между ними очень значительны. Что стабильно работает под одной осью, может падать под другой, особенно если она перегружена кучей конфликтующих приложений. Ладно, если это кривая программа Васи Пупкина (тут на пользователя можно и наехать), но если ваша программа не уживается в MS Office или другими продуктами крупных фирм, бить будут вас. Никогда не меняйте конфигурацию системы в процессе тестирования! Тогда будет трудно установить, чей это баг. Хорошая штука - виртуальные машины (VM Ware, Microsoft Virtual PC). На одном компьютере можно держать множество версий операционных систем с различной комбинацией установленных приложений - от стерильной до полностью захламленной. При возникновении ошибки состояние системы легко сохранить на жесткий диск, обращаясь к нему впоследствии столько раз, сколько потребуется.

Понравилась статья? Поделиться с друзьями: