Python уроки: Введение в тестирование на Python

Введение

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

Определение

Тестирование программного обеспечения (Software Testing) - проверка соответствия между реальным и ожидаемым поведением программы, осуществляемая при конечном наборе тестов, выбранном определенным образом. [IEEE Guide to Software Engineering Body of Knowledge, SWEBOK, 2004]

В более широком смысле, тестирование - это одна из техник контроля качества, включающая в себя действия по планированию работ (Test Management), проектированию тестов (Test Design), выполнению тестирования (Test Execution) и анализу полученных результатов (Test Analysis).

Для разработчика же интересней следующее определение:

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

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

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

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

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

Например, функция, которая возвращает числовое значение от 0 до 100. В тестах стоит проверить не только правильность значений из этого диапазона, но и то, что других значений не возникает.

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

Тестирование смело делится на несколько уровней глубины. Наиболее показательная классификация по уровням тестирования в данном случае такая:

  • Системное тестирование – тестирование полностью интегрированного программного приложения
  • Интеграционное тестирование – тестирование интегрированных групп программных модулей
  • Модульное тестирование или юнит-тестирование – тестирование отдельных модулей исходного кода приложения

Когда говорят "тестирование" не выделяя конкретный тип, то говорят скорее всего о модульном тестировании.

Пойдем с низу вверх (от 3 к 1)

Модульное тестирование

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

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

Инструменты

В Python для модульного тестирования применяют

  • PyUnit
  • PyTest
  • Nose

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

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

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

Подходы к интеграционному тестированию:

  • Снизу вверх (Bottom Up Integration)
    • Все низкоуровневые модули, процедуры или функции собираются воедино и затем тестируются. После чего собирается следующий уровень модулей для проведения интеграционного тестирования. Данный подход считается полезным, если все или практически все модули разрабатываемого уровня готовы.
  • Сверху вниз (Top Down Integration)
    • Вначале тестируются все высокоуровневые модули, и постепенно, один за другим добавляются низкоуровневые. Все модули более низкого уровня симулируются заглушками с аналогичной функциональностью, затем по мере готовности они заменяются реальными активными компонентами.
  • Большой взрыв ("Big Bang" Integration)
    • Все или практически все разработанные модули собираются вместе в виде законченной системы или ее основной части, и затем проводится интеграционное тестирование. Такой подход очень хорош для сохранения времени. Однако, если тест кейсы и их результаты записаны не верно, то сам процесс интеграции сильно осложнится, что станет преградой для команды тестирования при достижении основной цели интеграционного тестирования

Инструменты

Для автоматизации интеграционного тестирования применяются системы непрерывной интеграции (Continuous Integration System, CIS). Принцип действия таких систем состоит в следующем:

  1. CIS производит мониторинг системы контроля версий;
  2. При изменении исходных кодов в репозитории производится обновление локального хранилища;
  3. Выполняются необходимые проверки и модульные тесты;
  4. Исходные коды компилируются в готовые выполняемые модули;
  5. Выполняются тесты интеграционного уровня;
  6. Генерируется отчет о тестировании.

Примеры инструментов:

  • Bamboo
  • Hudson и Jenkins
  • CruiseControl
  • TeamCity
  • BuildBot
  • Travis CI
  • Team Foundation Server

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

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

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

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

Стоит выделить два подхода к системному тестированию:

  • на базе требований (requirements based). Для каждого требования пишутся тестовые случаи (test cases), проверяющие выполнение данного требования.
  • на базе случаев использования (use case based). На основе представления о способах использования продукта создаются случаи использования системы (Use Cases).

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

Инструменты

Для описания сценариев можно использовать BDD ( behavior-driven development)

  • pytest-bdd
  • behave
  • freshen

Простой инструмент проверки данных - assert

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

Python - язык с динамической типизацией. Это значит, что при написании Python-кода мы явно не указываем тип данных, а во время исполнения не гарантируется явный тип переменной.

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

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

Assert'ы позволяют отлавливать ошибки в программах на этапе компиляции либо во время исполнения.

Использование конструкции весьма простое:

# -*- encoding: utf-8 -*-

def simple_func(value):
    assert type(value) == int
    assert value > 0

    return value*value

Assert вызывает ошибку если аргумент равен False. Например так:

print(simple_func(2))

>> 4

print(simple_func(set()))

>> Traceback (most recent call last):
>>   File "/tmp/testing/app.py", line 11, in <module>
>>     print(simple_func(set()))
>>    File "/tmp/testing/app.py", line 4, in simple_func
>>      assert type(value) == int
>>  AssertionError

print(simple_func(-1))

>>  Traceback (most recent call last):
>>    File "/tmp/testing/app.py", line 21, in <module>
>>      print(simple_func(-1))
>>    File "/tmp/testing/app.py", line 5, in simple_func
>>      assert value > 0
>>  AssertionError

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

Выводы

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

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

Рейтинг
Текущий рейтинг: 4,4


Комментарии

Python-конференция

Теги

notify, os, isinstance, encode, database, all, многопоточность, mail, срез, сборник, pytest, новый год, конкурентность, аргумент, pycon, gevent, GIL, интерпретатор, python проект, игры, замыкание, copy, функциональное программирование, pynotify, pypi, типы данных, csv, график, testing, поиск ошибок, автоматизация, ardruio, swagger, память, файл, pip, тест, web, статический анализ, dsl, syntax, отчет, список, ide, графика, notification, rest, pycallgraph, githook, generic, hook. webhook, история, asyncio, logging, инструмент, swig, click, crawler, while, aiohttp, clonedigger, оптимизация, трансдьюсер, matplotlib, Бизли, bottle, концепция, типизация, fuzzy-testing, урок, language, путь, nose, image, тестирование, консоль, vk, c, list, operator, pylint, print, практика, сравнение, functools, измерение, польза, selenium, сопроцедуры, генерация данных, БД, мастер класс, plotly, tests, bokeh, генерация, производительность, winapi, flask, typing, strip, lxml, grab, scandir, Qt, pycharm, проект, книга, dictwriter, coverage, html, фп, pypy, signal, стандартная библиотека, now, weakref, google, практика программирования, corotine, sqlalchemy, nameko, синтаксис, import, паттер, virtualenv, api, зеленый поток, timeit, контекст, бд, funcy, encoding, кэш, json, статистика, байт-код, unittest, кодировка, opencv, datetime, ооп, itertools, package, fp, mixin, python, assert, pyqt, утка, garbage collector, курс, frozenset, numpy, django-debug-toolbar, терминал, xpath, closure, type, дубликат, requirements, статическая типизация, PIL, работа, debug, быстродействие, plot, рейтинг, водяной знак, ip, python3, yield from, видео, test, fuzzy, curses, gitter, unicode, decode, cache, twitter, pep, вконтакте, операционная система, ОС, тесты, any, awesome, задача, последовательность, geoip, ошибки, генератор, hardcore, toolbar, Wx, qt, магия, doctest, железо, marshal, множество, сигнал, greenlet, слайс, future, db, время, admin, pyside, regex, module, slots, примесь, sys, email, action, requirementstxt, регулярные выражения, дубликат кода, одноплатный компьютер, scrapinghub, micropython, фича, mock, raspberry pi, foreign key, ссылка, django, нг, pickle, модуль, celery, справочник, импорт, лямбда, rpc, with, наука, jinja2, log, обработка текста, super, set, svg, матрица, pygame, fixture, docstring, fabric, декларативный язык, пакет, опыт, магическая переменная, regexp, Гвидо, slice, gui, база данных, vkcom, юникод, yattag, ospath, cython, unit, maxmind, матан, документация, анализатор, Tags, менеджер контекста, yield, учебник, real-time, слабая ссылка, IPython, браузер, xml, GUI, gc, channel, машинное обучение, zip, библиотека, ошибка, данные, оповещение, парсинг, изображение, CLI, tox, фильтр, R, feedly, cffi, http, таблицы, python2, gunicorn, стандарт, if, requests, rss, tkinter, time, mechanize, gensim, интерфейс, enum, визуализация, postgresql, web parsing, язык, исключение, архитектура, lstrip, parsing, путь до файла, copy paste, multiprocessing, rstrip, статический анализатор, lambda