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

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

Рубрика Программирование, компьютеры и кибернетика
Вид курсовая работа
Язык русский
Дата добавления 17.04.2011
Размер файла 105,2 K

Отправить свою хорошую работу в базу знаний просто. Используйте форму, расположенную ниже

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

Размещено на http://www.allbest.ru/

74

МИНИСТЕРСТВО ОБРАЗОВАНИЯ РЕСПУБЛИКИ БЕЛАРУСЬ Витебский государственный университет им. П.М. Машерова

Кафедра прикладной математики и механики

Курсовая работа

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

Студент гр. П41

А.М. Бомко

Содержание

1. Основы тестирования программного обеспечения

  • 1.1 История развития тестирования программного обеспечения
    • 1.2 Основные определения в области тестирования программного обеспечения. Цели и задачи тестирования
    • 1.3 Классификация тестирования
    • 1.4 Классификация ошибок
    • 1.5 Список вопросов для выявления ошибок в начале процесса тестирования
    • 2. Практическое применение
    • 2.1 C чего начать?
    • 2.2 Тестирование приложения «Определение типа треугольника»
    • 2.3 Тестирование приложения «Библиотека»
    • 3. Тестирование при разработке программного обеспечения
    • 3.1 Модульное тестирование
    • 3.2 Цели создания тестов
    • 3.3 JUNIT
    • Заключение
    • Список использованных источников
    • Приложение

Введение

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

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

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

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

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

Еще одна причина, по которой трудно говорить о тестировании - это тот факт, что о нем известно очень немногое. Если сегодня общество располагает около 5% тех знании о проектировании и собственно программировании (кодировании), то о тестировании известно менее 1%.

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

Целью курсовой работы является изучение основ тестирования программного обеспечения. Задачи: изучить предложенную литературу по тестированию программного обеспечения, выделить основные этапы тестирования, составить методические материалы по теме «Тестированию программного обеспечения», провести тестирование двух приложений, используя полученные знания, изучить оcновы модульного тестирования на основе оболочки JUnit.

1. Основы тестирования программного обеспечения

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

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

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

В начале 1970-х тестирование программного обеспечения обозначалось как «процесс, направленный на демонстрацию корректности продукта» или как «деятельность по подтверждению правильности работы программного обеспечения». В зарождавшейся программной инженерии верификация программного обеспечения значилась как «доказательство правильности». Хотя концепция была теоретически перспективной, на практике она требовала много времени и была недостаточно всеобъемлющей. Было решено, что доказательство правильности - неэффективный метод тестирования программного обеспечения. Однако, в некоторых случаях демонстрация правильной работы используется и в наши дни, например, приемо-сдаточные испытания. Во второй половине 1970-х тестирование представлялось как выполнение программы с намерением найти ошибки, а не доказать, что она работает. Успешный тест - это тест, который обнаруживает ранее неизвестные проблемы. Данный подход прямо противоположен предыдущему. Указанные два определения представляют собой «парадокс тестирования», в основе которого лежат два противоположных утверждения: с одной стороны, тестирование позволяет убедиться, что продукт работает хорошо, а с другой - выявляет ошибки в программном обеспечении, показывая, что продукт не работает. Вторая цель тестирования является более продуктивной с точки зрения улучшения качества, так как не позволяет игнорировать недостатки программного обеспечения.

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

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

В 2000-х появилось еще более широкое определение тестирования, когда в него было добавлено понятие «оптимизация бизнес-технологий» (BTO). BTO направляет развитие информационных технологий в соответствии с целями бизнеса. Основной подход заключается в оценке и максимизации значимости всех этапов жизненного цикла разработки программного обеспечения для достижения необходимого уровня качества, производительности, доступности. [7]

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

Тестирование программного обеспечения (software testing) - это процесс анализа или эксплуатации программного обеспечения с целью выявления дефектов. Несмотря на всю простоту этого определения, в нем содержатся пункты, которые требуют дальнейших пояснений. Слово процесс (process) используется для того, чтобы подчеркнуть, что тестирование суть плановая, упорядоченная деятельность.[2]

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

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

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

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

1.3 Классификация тестирования

По знанию внутренностей системы:

- черный ящик;

- серый ящик;

- белый ящик.

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

- функциональное тестирование;

- тестирование интерфейса пользователя;

- тестирование локализации;

- тестирование скорости и надежности;

- тестирование безопасности;

- тестирование опыта пользователя;

- тестирование совместимости.

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

- альфа-тестировщик;

- бета-тестировщик.

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

- до передачи пользователю - альфа-тестирование;

- тест приемки;

- тестирование новых функциональностей;

- регрессивное тестирование;

- тест сдачи;

- после передачи пользователю - бета-тестирование.

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

- позитивное тестирование;

- негативное тестирование.

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

- компонентное тестирование;

- интеграционное тестирование;

- системное тестирование.

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

- ручное тестирование;

- автоматизированное тестирование;

- смешанное/полуавтоматизированное тестирование.

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

- тестирование по документации;

- эд хок-тестирование.[5]

По знанию внутренностей системы

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

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

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

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

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

Альфа-тестировщик. Альфа-тестирование - имитация реальной работы с системой штатными разработчиками, либо реальная работа с системой потенциальными пользователями/заказчиком.[7] Альфа-тестировщик - это сотрудники компании, которые профессионально или непрофессионально проводят тестирование: тестировщики, программисты, продюсеры, бухгалтеры, сисадмины, секретарши. [5]

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

По степени изолированности тестируемых компонентов

Компонентное тестирование - это тестирование на уровне логического компонента. И это тестирование самого логического компонента.

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

Системное тестирование - это проверка всей системы от начала до конца.[5]

1.4 Классификация ошибок

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

Для классификации ошибок мы должны определить термин «ошибка».

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

Итак, по времени появления ошибки можно разделить на три вида:

- структурные ошибки набора;

- ошибки компиляции;

- ошибки периода выполнения.

Структурные ошибки возникают непосредственно при наборе программы. К данному типу ошибок относятся такие как: несоответствие числа открывающих скобок числу закрывающих, отсутствие парного оператора (например, try без catch).

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

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

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

В теоретической информатике программные ошибки классифицируют по степени нарушения логики на:

- синтаксические;

-семантические;

- прагматические.

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

- пропуск необходимого знака пунктуации;

- несогласованность скобок;

- пропуск нужных скобок;

- неверное написание зарезервированных слов;

- отсутствие описания массива.

Все ошибки данного типа обнаруживаются компилятором.

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

GregorianCalendar.add(1, Calendar.MONTH).

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

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

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

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

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

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

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

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

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

Ошибка описания данных - ошибка, допущенная в ходе описания данных.[2]

1.5 Список вопросов для выявления ошибок в начале процесса тестирования

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

Ошибки обращения к данным

Сводный список вопросов таков:

1. Используются ли переменные с неустановленными значениями?

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

2. Лежат ли индексы вне заданных границ?

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

3. Есть ли нецелые индексы?

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

4. Есть ли «подвешенные» обращения?

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

Этот тип ошибок характерен для языка Си или С++, где широко используются ссылки и указатели. Язык Java в этом отношении более развит, например, при потере всех ссылок на объект, объект переходит в «кучу мусора», где автоматически освобождается память из-под объекта (объект удаляется) специальным сборщиком мусора. Последние изменения в языке С++, выполненные командой разработчиков Microsoft, которые преобразовали этот язык в С#, реализуют похожий механизм.

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

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

6. Превышены ли границы строки?

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

Ошибки описания данных

Сводный список вопросов таков:

1. Все ли переменные описаны?

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

2. Правильно ли инициализированы объекты, массивы и строки?

Если начальные значения присваиваются переменным в операторах описания, то правильно ли инициализируются эти значения? Правильно ли создаются объекты, используется ли соответствующий конструктор?

3. Понятны ли имена переменных?

Наличие переменных с бессмысленными именами (например, i и j) не является ошибкой, но является объектом пристального внимания. Классически i и j являются цикловыми переменными, а вот названий типа t125 следует избегать, так как возможна путаница имен.

4. Нельзя ли обойтись без переменных со сходными именами?

Есть ли переменные со сходными именами (например, user и users)? Наличие сходных имен не обязательно является ошибкой, но служит признаком того, что имена могут быть перепутаны где-нибудь внутри программы.

5. Корректно ли произведено описание класса?

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

Ошибки вычислений

Сводный список вопросов таков:

1. Производятся ли вычисления с использованием данных разного типа?

Существуют ли вычисления, использующие данные разного типа? Например, сложение переменной с плавающей точкой и целой переменной. Такие случаи не обязательно являются ошибочными, но они должны быть тщательно проверены для обеспечения гарантии того, что правила преобразования, принятые в языке, понятны. Это важно как для языков с сильной типизацией (например, Ada, Java), так и для языков со слабой типизацией (например, С++, хотя он тяготеет к сильной типизации). Ошибки, связанные с использованием данных разных типов, являются одними из самых распространенных.

2. Производятся ли вычисления неарифметических переменных?

3. Возможно ли переполнение или потеря промежуточного результата при вычислении?

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

4. Есть ли деление на ноль?

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

5. Существуют ли неточности при работе с двоичными числами?

6. Не выходит ли значение переменной за пределы установленного диапазона?

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

7. Правильно ли осуществляется деление целых чисел?

Встречается ли неверное использование целой арифметики, особенно деления? Например, если i - целая величина, то выражение 2*i/2 = i зависит от того, является значение i четным или нечетным, и от того, какое действие - умножение или деление - выполняется первым.

Ошибки при сравнениях

Сводный список вопросов таков:

Сравниваются ли величины несовместимых типов? Например, число со строкой?

2. Сравниваются ли величины различных типов?

Например, переменная типа int с переменной типа long? Каждый язык ведет себя в этих случаях по-своему, проверьте это по его описанию. Как выполняются преобразования типов в этих случаях?

3. Корректны ли отношения сравнения?

Иногда возникает путаница понятий «наибольший», «наименьший», «больше чем», «меньше чем».

4. Корректны ли булевские выражения?

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

5. Понятен ли порядок следования операторов?

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

(А == 2) && (В == 2) || (С == 3),

понятно ли, какая из операций выполняется первой: И или ИЛИ?

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

Влияет ли на результат выполнения программы способ, которым конкретный компилятор выполняет булевские выражения? Например, оператор

if ((x!= 0) && ((y/x) > z)) 38

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

Ошибки в передачах управления

Сводный список вопросов таков:

1. Может ли значение индекса в переключателе превысить число переходов? Например, значение переключателя для оператора select case.

2. Будет ли завершен каждый цикл?

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

3. Будет ли завершена программа? Будет ли программа, метод, модуль или подпрограмма в конечном счете завершена?

4. Существует ли какой-нибудь цикл, который не выполняется из-за входных условий?

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

5. Есть ли ошибки отклонения числа итераций от нормы?

Существуют ли какие-нибудь ошибки «отклонения от нормы» (например, слишком большое или слишком малое число итераций)?

Ошибки интерфейса

Сводный список вопросов таков:

Равно ли число входных параметров числу аргументов?

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

2. Соответствуют ли единицы измерения параметров и аргументов?

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

3. Не изменяет ли метод аргументы, являющиеся только входными?

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

5. Ошибки ввода-вывода

Сводный список вопросов таков:

1. Правильны ли атрибуты файлов? Не происходит ли запись в файлы read-only?

2. Соответствует ли формат спецификации операторам ввода-вывода? Не читаются ли строки вместо байт?

3. Соответствует ли размер буфера размеру записи?

4. Открыты ли файлы перед их использованием?

5. Обнаруживаются ли признаки конца файла?

6. Обнаруживаются ли ошибки ввода-вывода? Правильно ли трактуются ошибочные состояния ввода-вывода?

7. Существуют ли какие-нибудь текстовые ошибки в выходной информации?

Существуют ли смысловые или грамматические ошибки в тексте, выводимом программой на печать или экран дисплея? Все сообщения программы должны быть тщательно проверены.[2]

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

2.1 C чего начать?

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

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

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

- совокупность выполняемых вами действий,

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

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

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

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

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

Рисунок 1. Архитектура тестов.

Хороший тест должен удовлетворять следующим критериям:

1. Существует обоснованная вероятность выявления тестом ошибки.

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

2. Набор тестов не должен быть избыточным.

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

3. Тест должен быть наилучшим в своей категории.

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

4. Он не должен быть слишком простым или слишком сложным.

Объединив два теста в один, можно сэкономить время на их выполнении. Но не переусердствуйте - огромный и сложный тест трудно понять, трудно выполнить и долго создавать. Поэтому лучше всего придерживаться золотой середины, разрабатывая простые, но все же не совсем элементарные тестовые примеры. Кроме трудоемкости, у сложных тестов есть и более серьезный недостаток. Скомбинировав несколько неверных входных значений, нельзя сказать наверняка, как программа интерпретирует каждое из них. После первого же недопустимого значения поведение программы может выйти из-под контроля, например, она может просто отказаться принимать все остальные данные.[6]

2.2 Тестирование приложения «Определение типа треугольника»

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

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

Проанализировав возможные ошибки можно составить следующие тесты.

1. Тест, который представляет правильный неравносторонний треугольник? (Тесты, со значениями 1, 2, 3 и 2, 5, 10 неудачны, так как не существует треугольников, имеющих такие стороны.).

2. Тест, который представляет правильный равносторонний треугольник?

3. Тест, который представляет правильный равнобедренный треугольник? (Тесты со значениями 2, 2, 4 принимать в расчет не следует.)

4. Три теста, которые представляют правильные равнобедренные треугольники, полученные перестановкой двух равных сторон треугольника (например, 3, 3, 4; 3, 4, 3 и 4, 3, 3).

5. Тест, в котором длина одной из сторон треугольника принимает нулевое значение.

6. Тест, в котором длина одной из сторон треугольника принимает отрицательное значение.

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

8. Три теста с заданными значениями всех трех перестановок, в которых длина одной стороны равна сумме длин двух других сторон (например, 1, 2, 3; 1, 3, 2 и 3, 1, 2).

9. Тест из трех целых положительных чисел, таких, что сумма двух из них меньше третьего числа (т. е. 1, 2, 4 или 12, 15, 30)?

10. Три теста из категории 9, в которых испытываются все три перестановки (например, 1, 2, 4; 1, 4, 2 и 4, 1, 2).

11. Тест, в котором все стороны треугольника имеют длину, равную нулю (т. е. 0, 0, 0).

12.Тест, содержащий нецелые значения.

13.Описали ли вы заранее в каждом тесте не только входные значения, но и выходные данные метода?

Для простоты просмотра результатов тестов используют таблицу. В таблице содержится следующая информация.

- ID тестового примера. Уникальный идентификационный номер тестового примера.

- Входные данные. Последовательность входных данных, которая вводится тестером.

- Ожидаемые результаты. Поведение системы, которое тестер ожидает увидеть.

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

Результаты тестирования показаны в таблице 2.1.

Таблица 2.1. Набор тестов для приложения «Определение типа треугольника»

ID тестового примера

Входные данные

Ожидаемые результаты

Реальные результаты

1 сторона

2 сторона

3 сторона

Т1

3

7

6

Сообщение, о том, что треугольник с введенными сторонами является неравносторонним

Т2

3

3

3

Сообщение, о том, что треугольник с введенными сторонами является равносторонним

Т3

6

6

3

Сообщение, о том, что треугольник с введенными сторонами является равнобедренным

Т4.1

3

3

4

Сообщение, о том, что треугольник с введенными сторонами является равнобедренным

Т4.2

3

4

3

Сообщение, о том, что треугольник с введенными сторонами является равнобедренным

Т4.3

4

3

3

Сообщение, о том, что треугольник с введенными сторонами является равнобедренным

Т5

0

3

4

Сообщение, о том, что треугольник с введенными сторонами не может быть построен

Т6

-1

3

5

Сообщение, о том, что треугольник с отрицательными сторонами не может быть построен

Т7

1

2

3

Сообщение, о том, что треугольник с введенными сторонами не может быть построен

Т8.1

1

3

2

Сообщение, о том, что треугольник с введенными сторонами не может быть построен

Т8.2

2

1

3

Сообщение, о том, что треугольник с введенными сторонами не может быть построен

Т8.3

3

2

1

Сообщение, о том, что треугольник с введенными сторонами не может быть построен

Т9

1

2

4

Сообщение, о том, что треугольник с введенными сторонами не может быть построен

Т10.1

4

2

1

Сообщение, о том, что треугольник с введенными сторонами не может быть построен

Т10.2

1

4

2

Сообщение, о том, что треугольник с введенными сторонами не может быть построен

Т10.3

4

1

2

Сообщение, о том, что треугольник с введенными сторонами не может быть построен

Т11

0

0

0

Сообщение, о том, что треугольник с отрицательными сторонами не может быть построен

Т12

4.6

2

3

Сообщение о том, что введено нецелое число

2.3 Тестирование приложения «Библиотека»

Пример требований к приложению «Библиотека»

В качестве примера для тестирования возьмем проект «Библиотека» (Приложение Б).

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

Вся доступная информация о проекте предоставлена в виде требований. Наша задача - проанализировать требования с последующим определением набора тестов.

Приложение «Библиотека» может выполнять 10 команд. Все команды вводятся пользователем с клавиатуры.

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

2. При вводе команды «test» приложение выводит сообщение «Неподдерживаемая команда».

3. С помощью команды «выход» производиться выход из приложения.

4. В результате ввода команды «добавить читателя» должно выдаваться сообщение «Ошибка! Вводите данные по следующему образцу: добавить читателя; фамилия; имя; отчество; пол; адрес; телефон» (Сообщение 1). То есть чтобы добавить читателя пользователь должен ввести данные следующего формата: «добавить читателя; фамилия; имя; отчество; пол; адрес; телефон». При вводе данной команды читатель сохраняется в текстовом файле «readers.txt», ему присваивается уникальный идентификационный номер, а на экран выдается сообщение «Читатель сохранен под номером …» (Сообщение 2), где вместо точек ставится идентификатор читателя. Если введенную информацию не удается сохранить, то выводиться сообщение «Не удалось сохранить читателя» (Сообщение 3).

5. Ввод команды «добавить книгу» также приводит к выводу сообщения: «Ошибка! Вводите данные по следующему образцу: добавить книгу; автор; название; жанр» (Сообщение 4). Следовательно, чтобы добавить книгу должна быть введена команда следующего вида: «добавить книгу; автор; название; жанр». При вводе данной команды книга сохраняется в файле «books.txt», ей присваивается уникальный идентификационный номер и на экран выводится «Книга сохранена под номером …» (Сообщение 5), где вместо точек ставится идентификатор книги. Если данные невозможно сохранить, то выводится сообщение «Не удалось сохранить книгу» (Сообщение 6).

6. Команда «выдать книгу». Вывод сообщения «Ошибка! Вводите данные по следующему образцу: выдать книгу;номер читателя;номер книги;дата возврата» (Сообщение 7). Таким образом, для того чтобы зарегистрировать выдачу книги пользователю надо ввести команду формата: «выдать книгу; номер читателя; номер книги; дата возврата». Если выдача осуществилась, то выдается сообщение «Выдача успешно зарегистрирована» (Сообщение 8) и информация сохраняется в файле «abonement.txt». В данную информацию входят: идентификатор выдачи, идентификатор читателя, идентификатор книги и период, на который выдана книга, где дата выдачи определяется по системным часам, а дата возврата вводится пользователем. При неверно введенной дате выводится сообщение «Неверно введена дата возврата» (Сообщение 9), если книга уже выдана - «Данная книга находится на руках» (Сообщение 10). Если читателя, которому хотят выдать книгу, нет в файле «readers.txt» или существующий читатель уже взял книгу, то при попытке выдать ему книгу выводится сообщение «Данного читателя не существует или ему не разрешена выдача книг» (Сообщение 11). Если регистрация выдачи книги не может осуществиться, то мы видим сообщение «Ошибка регистрации выдачи книги» (Сообщение 12).

7. Команда «вернуть книгу». При вводе видим сообщение «Ошибка! Вводите данные по следующему образцу вернуть книгу;номер книги» (Сообщение 13). Если данные введены согласно данному формату, то выводится «Возврат книги зарегистрирован» (Сообщение 14). Если же введен номер книги, о которой нет информации в файле «readers.txt», то выводится «Ошибка регистрации возвращенной книги. Возможно нет данных по этой книге» (Сообщение 15).

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

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

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

11. Если пользователь ввел неподдерживаемую программой команду, то выдается сообщение «Неподдерживаемая команда» (Сообщение 16).

Выделение требований

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

Таблица 2.2. Описание приложения с разбиением на пункты

Номер

Описание

Т1

Пользователь может посмотреть весь список команд

Т2

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

Т3

Пользователь может добавить читателя

Т4

Пользователь может добавить книгу

Т5

Пользователь может выдать книгу читателю

Т6

Пользователь может зарегистрировать возврат книги

Т7

Пользователь может посмотреть список зарегистрированных читателей

Т8

Пользователь может организовать поиск читателя по введенной фамилии

Т9

Пользователь может организовать поиск читателя по введенному идентификатору

Т10

Пользователь может посмотреть список зарегистрированных не выданных книг

Т11

Пользователь может организовать поиск книги по введенной фамилии автора

Т12

Пользователь может организовать поиск книги по введенному идентификатору

Т13

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

Т14

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

Категории тестов

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

Категории тестов, рассматриваемые при разработке тестовых примеров, включают следующие ситуации:

- нет данных;

- повторное выполнение;

- верные данные;

- неверные данные;

- сброс;

- потеря мощности;

- создание напряжений в системе;

- тестирование характеристик;[8]

- ошибки, описки и нарушения логики в сообщениях, выдаваемых программой.

1. Категория тестов «Нет данных».

Возможные вопросы:

- Как можно «подвесить» систему?

- Что случится, если не ввести данные?

- Что означает утаивание данных?

- Каково значение или состояние по умолчанию?

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

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

- отправить сообщение об ошибке;

- установить значение, заданное по умолчанию;

- повторно использовать предыдущие данные или состояние;

- напомнить пользователю об отсутствии данных;

- аннулировать транзакцию;

- прервать выполнение.[8]

В проекте «Библиотека», если пользователь нажал клавишу <ENTER> без введенных данных, приложение расценивает это как неподдерживаемую команду и выводит сообщение «Неподдерживаемая команда».

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

2. Категория тестов «Повторное выполнение»

Возможные вопросы:

Что случится, если два раза подряд будут представлены одни и те же данные или же ввод будет сделан дважды?

Что случится, если повторить предыдущее состояние?

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

Ожидается, что система может повести себя следующим образом:

- отправить сообщение об ошибке;

- перезаписать предыдущее значение или состояние;

- предложить пользователю подтвердить перезапись предыдущего значения или состояния;

- обработать второй запрос как отдельное независимое событие.[8]

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

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

3. Категория тестов «Верные данные»

Возможные вопросы:

- Что такое верные экземпляры этих данных?

- Каков диапазон верных значений входных данных?

- Каковы граничные значения данных?

- Каков формат верного пакета?

- Какая информация передается при верной транзакции?

Тестовый пример, построенный на основе верных данных, подтверждает, что приложение корректно обрабатывает информацию. Значения неверных данных попадают в категорию «Неверные данные».[8]

В проекте «Библиотека», если пользователь ввел верные данные при добавлении читателя, книги, при выдаче книги, то создаются текстовые документы «readers.txt», «books.txt», «abonement.txt» соответственно. Также из требований известен образец ввода данных, однако какие данные являются верными не указано. Таким образом, требования неполны. Возникают вопросы:


Подобные документы

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

    курсовая работа [309,5 K], добавлен 16.12.2015

  • Неразрешимость проблемы тестирования программного обеспечения. Виды и уровни тестирования. Стратегии восходящего и нисходящего тестирования. Методы "белого" и "черного" ящика. Автоматизированное и ручное тестирование. Разработка через тестирование.

    курсовая работа [112,2 K], добавлен 22.03.2015

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

    курсовая работа [3,0 M], добавлен 19.11.2009

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

    курсовая работа [1,6 M], добавлен 20.12.2012

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

    дипломная работа [1,7 M], добавлен 03.05.2018

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

    курсовая работа [303,4 K], добавлен 19.01.2016

  • Выбор инструментальной среды разработки программного обеспечения системы. Алгоритм создания теста и ввода его исходных данных. Анализ экономической эффективности применения программного обеспечения "Тестирования знаний обучающихся программированию".

    дипломная работа [3,2 M], добавлен 11.09.2014

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

    курсовая работа [2,8 M], добавлен 05.01.2013

  • Проектирование базы данных, информационной подсистемы PLC-Tester, модуля тестирования и web-приложения. Разработка логической структуры программного продукта и общие требования к техническому обеспечению. Запуск программы и описание тестовых прогонов.

    дипломная работа [3,2 M], добавлен 30.06.2011

  • Описание исходных текстов программного продукта. Системные требования и установка программного продукта. Тестирование пользователя по двадцати вопросам указанной темы и сохранение результатов тестирования. Форма отображения результатов тестирования.

    курсовая работа [2,8 M], добавлен 09.07.2013

Работы в архивах красиво оформлены согласно требованиям ВУЗов и содержат рисунки, диаграммы, формулы и т.д.
PPT, PPTX и PDF-файлы представлены только в архивах.
Рекомендуем скачать работу.