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

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

В чем важность модульного тестирования?

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

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

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

В Python для создания тестов есть много инструментов. Некоторые из них, такие как pytest, заменяют встроенный фреймворк unittest. Другие инструменты, такие как nose, являются расширениями, облегчающими создание тестовых случаев. Имейте в виду, что многие из этих инструментов также используются для интеграционного тестирования: с их помощью создаются тестовые случаи (test cases) для проверки одновременной работы нескольких частей кода.

  • unittest — это встроенный в стандартную библиотеку инструмент для тестирования кода на Python.
  • pytest — инструмент тестирования с упором на обратную совместимость и минимизацию бойлерплейт-кода.
  • nose — это расширение unittest, облегчающее создание и выполнение test cases.
  • Hypothesis — библиотека Python для создания юнит-тестов. Помогает разработчикам создавать тесты с крайними случаями. Лучший способ начать использовать Hypothesis — воспользоваться хорошо написанным «быстрым стартом».
  • mimesis генерирует синтетические тестовые данные, которые можно с пользой применить в ваших тестах.
  • testify — это тестовый фреймворк, предназначавшийся для замены распространенной комбинации unittest+nose. Но команда, занимавшаяся testify, переходит на pytest, так что использовать этот фреймворк для новых проектов не рекомендуется.

Ресурсы по модульному тестированию

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

  • Статья Introduction to Unit Testing («Введение в модульное тестирование») это развернутое вступление, в котором рассказывается о важности юнит-тестов и о том, с чего начать тестирование в ваших проектах.
  • Unit Testing Your Twilio App Using Python’s Flask and Nose («Модульное тестирование вашего Twilio-приложения с использованием Flask и Nose») это подробное руководство по использованию nose для проверки правильности работы приложения на Flask.
  • В статье Understanding unit testing («Разбираемся с модульным тестированием») объясняется, в чем важность модульного тестирования, и показывается, как эффективно тестировать ваши приложения.
  • Туториал Unit testing with Python («Модульное тестирование с Python») дает высокоуровневый обзор темы и на диаграммах показывает, что происходит в цикле тестирования.
  • На wiki Python есть страница со списком инструментов тестирования Python и полезных расширений.
  • An Extended Introduction to the nose Unit Testing Framework («Расширенное вступление к Nose — фреймворку модульного тестирования») показывает, как этот инструмент используется для написания базовых наборов тестов. Несмотря на то, что статья вышла еще в 2006 году, она все еще подходит для изучения работы nose.
  • Revisiting Unit Testing and Mocking in Python («Переосмысление юнит-тестов и мокинга в Python») — отличный пост со множеством примеров кода. В посте показано, как и зачем при создании модульных тестов используются dependency injection и @property.
  • Статья Unit Testing Doesn’t Affect Codebases the Way You Would Think («Модульное тестирование влияет на кодовую базу совсем не так, как вам кажется») рассказывается, какое воздействие модульное тестирование оказывает на код проекта (и какого воздействия ждать не стоит). Это лишь отчет о проведенном исследовании, но вывод о том, что увеличение количества юнит-тестов приводит к росту цикломатической сложности для каждого метода, довольно интересен.
  • Python unittest with Robert Collins — запись интервью с Робертом Коллинзом, основным разработчиком unittest.
  • Precise Unit Tests with PyHamcrest («Точные юнит-тесты с PyHamcrest») — это короткое руководство по использованию инструмента PyHamcrest в модульном тестировании.
  • Why most unit testing is a waste («Почему модульное тестирование это по большей части напрасная трата времени и сил») рассказывает, почему юнит-тесты с низким уровнем риска редко дают сбой даже при изменении кода и почему они не так важны для здоровья проекта, как полагают многие разработчики, руководствуясь догмами TDD.
  • В статье Writing Unit Tests for Django Migrations («Пишем юнит-тесты для Django-миграций») разбираются примеры кода для тестирования миграции данных в Django.
  • В статье The business case for unit testing («Модульное тестирование с точки зрения бизнеса») приводятся аргументы, с помощью которых можно убедить менеджмент в необходимости юнит-тестов.
  • Для модульного тестирования часто бывают необходимы наборы поддельных данных, которые в обычных условиях генерировались бы пользователем или другими частями системы. Инструменты для генерации этих данных могут избавить вас от необходимости создавать их самостоятельно. В этом посте рассказывается о генерации фейковых данных при помощи такого инструмента как Faker.
  • Статья Unit Testing Applications that use Flask-Login and Flask-SocketIO («Приложения модульного тестирования, использующие Flask-Login and Flask-SocketIO») объясняет, как настроить модульный тест WebSockets при помощи пары обычных библиотек Flask.