Connect with us

Обучение

Заметки Python #19: Тестирование

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

Тестирование на Python

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

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

Несмотря на то, что в Python собственный оператор assert для тестирования кода, мы будем опираться на модульное тестирование с помощью библиотеки юнит-тестов unittest. Модульное тестирование позволяет писать тесты в отдельном модуле (файле .py), чтобы не захламлять основной код программы — сильно важно при работе с большими проектами. Правилом хорошего тона считается полностью отделить подготовленные тесты от написанного программного кода. Для каждого программного пакета следует создать отдельный каталог, в котором будут располагаться его тесты. Модулям пакета должны соответствовать файлы с программным кодом, а каждому из них — файлы с тестовым классом. Если в пакете реализовано четыре Python-модуля: file_1.py, file_2.py, file_3.py, file_4.py, — в нем должен быть каталог с четырьмя тестовыми файлами. Название каждого из них должно начинаться с «test» и содержать наименование модуля: test_ file_1.py, test_ file_2.py, test_ file_3.py, test_ file_4.py.

Почему не assert?

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

Что такое юнит-тесты?

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

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

Модуль unittest

Библиотека юнит-тестов unittest создана специально для автоматизации тестирования и легкой интеграции конкретного теста в существующий код. Данный модуль  является встроенным — его не нужно устанавливать дополнительно. Как работает unittest?

  1. Испытательный стенд (test fixture) — в рамках данной концепции настраиваются тесты и операции, выполняемые по их завершении — например, генерация временных баз данных и старт серверного процесса.
  2. Тестовый случай (test case) — определяет блок тестирования. Выполняет проверку ответов для различных наборов данных. В модуле unittest реализован базовый класс TestCase, используемый для подготовки новых тестовых случаев.
  3. Набор тестов (test suite) — набор тестовых случаев или самих тестов. Объединяет тесты, которые выполняются вместе.
  4. Исполнитель тестов (test runner) — компонент, контролирующий выполнение тестов и предоставляющий результат пользователю. Может работать через графический или текстовый интерфейс и возвращать специальный объект с сообщением о результате тестирования.

Пример тестирования с помощью unittest

Модуль unittest опирается на объявление класса, производного от unittest.TestCase. Отдельные тесты определяются как методы, имена которых начинаются со слова test: testsimplestring, testtypeconvert и так далее. Важно отметить, что имена методов могут выбираться произвольно — главное, чтобы они начинались со слова test. Внутри каждого теста выполняются проверки условий.

 

Результат:

При использовании среды разработки PyCharm можно запускать отдельные тесты прямо из рабочей области:

Суть каждого теста — вызов assertEqual() для проверки ожидаемого результата; assertTrue() или assertFalse() для проверки условия; assertRaises() для проверки, что метод порождает исключение. Эти методы используются вместо обычного assert для того, чтобы исполнитель тестов смог взять все результаты и оформить отчёт.

Какие методы можно использовать в unittest.TestCase?

Экземпляр t класса unittest.TestCase имеет следующие методы, которые могут использоваться для тестирования и управления этим процессом:

  • t.setUp() — применяется для настройки перед вызовом любых методов тестирования;
  • t.tearDown() — вызывается для заключительных действий после выполнения всех тестов;
  • t.assert_(expr [, msg]) / t.failUnless(expr [, msg]) — сообщает об ошибке тестирования, если выражение expr оценивается как False. msg — это строка сообщения, объясняющая причины ошибки (если задана);
  • t.assertEqual(x, y [,msg]) / t.failUnlessEqual(x, y [, msg]) — сообщает об ошибке тестирования, если x и y не равны;
  • t.assertNotEqual(x, y [, msg]) / t.failIfEqual(x, y, [, msg]) — сообщает об ошибке тестирования, если x и y равны;
  • t.assertAlmostEqual(x, y [, places [, msg]]) / t.failUnlessAlmostEqual(x, y, [, places [, msg]]) — сообщает об ошибке тестирования, если числа x и y не совпадают с точностью до знака places после десятичной точки. Проверка выполняется за счет вычисления разности между x и y и округления результата до указанного числа знаков places после десятичной точки. Если результат равен нулю, числа x и y можно считать почти равными;
  • t.assertNotAlmostEqual(x, y, [, places [, msg]]) / t.failIfAlmostEqual(x, y [, places [, msg]]) — сообщает об ошибке тестирования, если числа x и y совпадают с точностью до знака places после десятичной точки;
  • t.assertRaises(exc, callable, …) / t.failUnlessRaises(exc, callable, …) — сообщает об ошибке тестирования, если вызываемый объект callable не выдает исключение exc. Остальные аргументы методов передаются callable. Для тестирования набора исключений в аргументе exc передается кортеж с этими исключениями;
  • t.failIf(expr [, msg]) — сообщает об ошибке тестирования, если выражение expr оценивается как True;
  • t.fail([msg]) — сообщает об ошибке тестирования;
  • t.failureException — в этом атрибуте сохраняется последнее исключение, перехваченное в тесте. Может использоваться, когда необходимо проверить, что исключение не только вызывается, но и сопровождается требуемым значением (например, сообщение, генерируемое исключением)

«Боевой» пример

Рассмотрим задачу, которая вполне может быть поставлена перед программистом в реальной жизни. Нужн написать программу для расчета заработной платы сотрудникам. Нам, как разработчикам, нужно сразу протестировать программу на предмет возможных ошибок. Здесь мы используем функцию namedturple из модуля collections для создания именованного кортежа. Подробнее о них можно почитать на хабре — https://habr.com/ru/post/330034/.

 

Результат:

Click to comment

Leave a Reply

Ваш e-mail не будет опубликован.

Лучшие сервисы стриминга музыки в 2019 году

Сервисы

Wink Ростелеком: Samsung LG, Sony, Phillips, Android TV

Ростелеком

LG WEB OS: приложения, обновления, настройка, проблемы со звуком

Гаджеты

Ноутбуки Asus не видят жесткий диск. Автоматический вход в BIOS при старте

Гаджеты

.

Digital2.ru - тренды, IT, разработка, цифровая экономика

Connect
Подпишись на нас