Pytest или unittest что выбрать
Python Unittest Vs Pytest: Choose the Best
Like any programming language, testing in python is checking individual units of source code. After the software is developed, it is important to test the source code by undergoing various forms of tests. With testing, we ensure that the code is working as expected and is free from any bugs. The main idea is to test it against several inputs. In this article, we shall be comparing two such testing methods – python unittest vs pytest.
Automated vs Manual Testing
There are two ways of performing testing in python – automated testing and manual testing. In manual testing, the code is tested manually by a human. The tester needs to manually make lists of all possible inputs and the expected output. It is a tedious job and also time-consuming.
This is where automated testing comes into play. Python consists of built-in frameworks that make testing code easier. Since automated testing is script-based, it is accurate. Python has tools and libraries – such as unittest and pytest.
Testing using Unittest framework
The unit testing framework in python is known as unittest. We can have a single function, a class, or an entire module as the unit for testing. The idea behind unit testing is to validate the smallest unit first and then gradually move to other units. The unittest in python is actually inspired by Java’s JUnit.
Outputs possible
Using the unittest framework, there are three possible outputs – OK, FAIL, and ERROR.
Test Code example
Let us consider a python code for running the tests. First, we will have to import the unittest module.
Now, we shall define a function named square() which takes a number ‘n’ as a parameter and returns the square of the number as the output.
Now, we will define a class named ‘Test’. The class test will inherit the unittest module by ‘unittest.TestCase’. We define a function inside the class named test_square. Here, the naming convention should be used such that the name ‘test’ precedes the function name.
We will pass ‘self’ as a parameter to the function. Inside the function, we will call self.assertEquals(). There are several assert methods present for testing, and assertEquals() is one of them. In assertEquals(), the first and the second argument should be equal for the test to be successful.
So here, we will pass the square(2) function as the first argument and 4 as the second argument.
To run the file ‘test_Calculation.py’, we shall use the following piece of code:
The output shall be:
Because the output of the function square(2) was equal to 4, the test ran successfuly and OK was printed.
Now, let us try to run two functions as two different test cases.
We shall define a second function named ‘cube’ which takes a single number as an argument and returns its cube as the output.
Now, inside the class Test, we shall define another function named test_cube(). We shall use self.assertEquals() and pass cube(2) and 8 as first and second arguments.
Now, we shall again run the same code in the terminal:
Since, there were two tests here, the output will be OK signifying that the two tests were run successfully.
The Entire Code is:
Failed Test Example
Now, we shall look into a scenario where the tests will fail. Let us take the same example as mentioned above. Inside the cube function, we will pass a string value as an argument instead of an integer.
On running the following code inside command line, the test will FAIL.
Output:
The output shows that two tests were run where one of them failed.
Testing Using Pytest framework
Pytest in python is another framework that is used for testing. With pytest, we can run several tests in parallel. Because of that a considerable amount of computation time is saved. Using pytest is simple and does not involve complex codes.
Pytest code example
Let us perform testing using pytest. For that, we simply have to define two functions – test_square() and test_cube(). Inside the test_square() function, we take a variable ‘n’ and return the square of that function ‘n’.
Similarly in test_cube() function we take variable ‘n’ and return the cube of that function ‘n’. We use assert statements to check if the respective conditions are True.
Inside the terminal for that file, we simply have to write pytest.
Since the assert statements output True values, the following output will be printed.
It shows that two items were collected successfully.
Failed Test example
Let us take an example where the assert conditions output False values. In that scenario, if the pytest command would be False then it would throw AssertionError and indicate that the tests FAILED.
The output is:
Python Unittest vs Pytest
Both unittest and pytest are testing frameworks in python. Unittest is the testing framework set in python by default. In unittest, we create classes that are derived from the unittest.TestCase module. It comes in handy because it is universally understood.
Whereas using pytest involves a compact piece of code. Pytest has rich inbuilt features which require less piece of code compared to unittest. In the case of unittest, we have to import a module, create a class and then define testing functions inside the class. But in the case of pytest, we have to define the functions and assert the conditions inside them.
Pytest Vs Unittest FAQs
Here are a few questions we often hear when comparing Pytest and Unittest.
Although both the frameworks are great for performing testing in python, pytest is easier to work with. The code in pytest is simple, compact, and efficient.
For unittest, we will have to import modules, create a class and define the testing functions within that class. But for pytest, we only have to define the testing function. Pytest is also fast and efficient.
This sums up the comparison between Python Unittest vs Pytest. If you have any questions in mind, leave them below in the comments.
Тестирование с помощью Python
Введение
Я начну с подготовки рабочей среды, затем перейдём к простым заданиям, которые могут поручить начинающему тестировщику.
На следующем этапе рассмотрим библиотеку unittest и изучим немного теории.
Статья рассчитана на начинающих тестировщиков. Для лучшего понимания некоторых частей желательно базовое знание Python
Использование Python для тестирования ПО.
Подготовка рабочей среды
sudo apt install python-pip
Если нужно обновить pip
pip install pipenv
pipenv install requests
На вашем компьютере может быть установлено несколько версий Python. Чтобы узнать какую версию используют ваши программы перейдтие по ссылке
Примеры программ
Создаем файл post.py и пишем следующий код
import requests r = requests.post(‘http://url.html’, data = <'site':'andreyolegovich.ru'>)
Реальный пример 1
Задача
Есть сервер, на котором отображаются подключённые устройства. Назовем его Менеджер_Устройств
Нужно, чтобы у каждого устройства был уникальный ID. Иначе получим ошибку.
Познакомившись с API этого сервера можно узнать, что запрос, которым добавляется новое устройство, выглядит следующим образом:
PUT to http://devm.com:4880/manager/rest/control/devices/Unique_ID/apps/Client_Name/status/$timestamp=Some_value
Также из API известно, что в этом запросе передаётся JSON
По заданию: itemModelId, itemDescription и uptime нужно делать уникальными.
Таким образом уникальных величины должно быть четыре.
Можно, конечно, посылать запросы из SOAP UI по одному, вручную изменяя Unique_ID, но это будет очень долго.
Пишем скрипт на Python, используя знания, полученные в начале этой статьи и в статье Python. Сначала импортируем нужные библиотеки.
Затем делим URL на три части: первая и третья остаются неизменными, а между ними мы будем вставлять переменую.
После этого запускаем цикл от 1 до 1000. Значения переменной i мы будем использовать для создания уникальных ID. С этой целью создадим три переменные: для наглядности они все будут заканчиваться на _var а затем я выделю их зелёным цветом.
Внимательно следим за отступами, т.к. отступ обозначает тело цикла.
import requests import json import urllib2 import uuid headers = <"Content-Type": "application/json">base_url=’http://device_manager.com:4880 / manager / rest /control / devices /’ end_url=’ / apps / Client_Name / status /$timestamp=1529086249′ for i in range(1,1000): c=str(i) item_model_var=»AASuperDevice»+c item_description_var=»Andrei»+c uptime_var=i * 50 Unique_ID_var=»Unique_ID»+c url=base_url+ str(Unique_ID_var)+end_url json_string= <"status": <«clientStatusData»: <"message":"Everything is OK", "status":"OK" >, «itemsStatuses»: [< "message":"URN.SU Server simulated", "status":"ENABLED", "name":"Connection", "Number":"0" >, < "message":"TopBicycle.RU Power: 250[mW], Session: 1", "status":"OK", "name":"AndreyOlegovih.ru", "Number":"1" >], «runningStatus»: < "restarted":"true", "uptimeMSec": uptime_var> >, «clientInfo»: <«applicationInfo»:<"applicationVersion":"19.61.04.12" >, «deviceInfo»: <"itemDescription": item_description_var, «itemModelId»: item_model_var, «statusUpdateIntervalMSec»:»30000″ > >, > data_json=json.dumps(json_string) r=requests.put(url, data=data_json, headers=headers)
Debugging
print («i =», i) print («i string=», c) print (item_model_var) print (u) print (uptime_var) print(r.text)
Но имейте в виду, что в серьёзном софте лучше делать отладку дебаггером.
Unittest
Unittest это библиотека для тестирования, которая входит в Python по умолчанию
Он содержит и тестовую среду, и Test Runner. У unittest есть ряд требований для написания и выполнения тестов:
*имеется в виду, что в unittest нужно для каждого типа утверждений использовать свой метод, например:
И так далее, подробности на сайте docs.python.org
Разберём простейший пример использования.
Создадим два файла calc.py и test_calc.py
Для запуска теста перейдём в директорию с файлами и в консоли выполним команду
Теперь можно запускать тест командой
Напишем тесты для всех функций из calc.py
Снова специально допустим ошибку, например, в третьем тесте
..F. означает, что первый, второй и четвёртый тесты прошли успешно, а в третьем ошибка
Assertion который вернул FALSE также видно
self.assertEqual(calc.multiply(10, 5), 70)
Имея такой подробный результат мы легко исправляем ошибку
self.assertEqual(calc.multiply(10, 5), 70)
self.assertEqual(calc.multiply(10, 5), 50)
Теория для unittest
Для тех, кто интересуется устарел ил unittest или нет, моё скромное мнение состоит в том, что нет.
Тем не менее unittest удобен тем, что он встроен в стандартную библиотеку и тем, что в других языках программирования тоже есть похожие фреймворки.
Test Fixture
Единичный тест называется тест кейсом (Test Case).
Часто нужно запустить несколько тест-кейсов, которым требуется для запуска одно и то же.
Например, получить один и тот же объет или запустить Selenium Webdriver или что-то другое.
Чтобы не писать в каждом тест-кейсе одно и то же можно воспользоваться методами setUp и tearDown которые создаются один раз для каждого класса и будут запускаться перед каждым тест-кейсом.
Такая комбинация setUp + tearDown называется Test Fixture
Test Fixture = setUp + tearDown
Составляющие части любого теста
Порядок выполнения тестов обычно следующий:
Подготовка к тесту
Непосредственное действие, например, запуск определённой функции
Проверка результата на соответствие ожиданию.
Arrange → Act → Assert
Длинных тестов в которых происходит множество чередующихся действий и проверок следует по возможности избегать.
Лучше написать несколько небольших тестов чем один длинный. Тогда при фэйле какого-то из хорошо структурированных тестов будет легче понять, что именно не работает.
Pytest
Главное преимущество Pytest заключается в особенностях написания TestCase.
TestCase в pytest — это серия функций в файле Python, которые начинаются с имени test_.
У Pytest есть и другие отличительные особенности:
Написание теста TestSum в pytest выглядит так:
def test_sum(): assert sum([1, 2, 3]) == 6, «Should be 6» def test_sum_tuple(): assert sum((1, 2, 2)) == 6, «Should be 6»
Здесь удалены базовый класс TestCase и любое использование классов в принципе, а также точка входа с командной строки. Как обычно, дополнительная информация представлена на сайте Pytest.
Добавить Pytest в Pycharm
Settings (Ctrl + Alt + S) → Tools → Python Integrated Tools → Default test runner:
Выбрать pytest. Если он ещё не был добавлен появится предупреждение и кнопка Fix.
Знакомство с тестированием в Python. Ч.1
От нашего стола к вашему. То есть от нашего курса «Разработчик Python», несмотря на стремительно приближающий Новый год, мы подготовили вам интересный перевод о различных методах тестирования в Python.
Это руководство для тех, кто уже написал классное приложение на Python, но еще не писал для
них тесты.
Тестирование в Python — обширная тема с кучей тонкостей, но не обязательно все усложнять. В несколько простых шагов можно создать простые тесты для приложения, постепенно наращивая сложность на их основе.
В этом руководстве вы узнаете, как создать базовый тест, выполнить его и найти все баги, до того как это сделают пользователи! Вы узнаете о доступных инструментах для написания и выполнения тестов, проверите производительность приложения и даже посмотрите на проблемы безопасности.
Тестирование Кода
Тестировать код можно разными способами. В этом руководстве вы познакомитесь с методами от наиболее простых до продвинутых.
Автоматизированное vs. Ручное Тестирование
Хорошие новости! Скорее всего вы уже сделали тест, но еще не осознали этого. Помните, как вы впервые запустили приложение и воспользовались им? Вы проверили функции и поэкспериментировали с ними? Такой процесс называется исследовательским тестированием, и он является формой ручного тестирования.
Исследовательское тестирование — тестирование, которое проводится без плана. Во время исследовательского тестирования вы исследуете приложение.
Чтобы создать полный список мануальных тестов, достаточно составить перечень всех функций приложения, различных типов ввода, которые оно принимает, и ожидаемые результаты. Теперь, каждый раз когда вы меняете что-то в коде, нужно заново проверять каждый из элементов этого списка.
Звучит безрадостно, верно?
Поэтому нужны автоматические тесты. Автоматическое тестирование — исполнение плана тестирования (части приложения, требующие тестирования, порядок их тестирования и ожидаемые результаты) с помощью скрипта, а не руками человека. В Python уже есть набор инструментов и библиотек, которые помогут создать автоматизированные тесты для вашего приложения. Рассмотрим эти инструменты и библиотеки в нашем туториале.
Модульные Тесты VS. Интеграционные Тесты
Мир тестирования полон терминов, и теперь, зная разницу между ручным и автоматизированным тестированием, опустимся на уровень глубже.
Подумайте, как можно протестировать фары машины? Вы включаете фары (назовем это шагом тестирования), выходите из машины сами или просите друга, чтобы проверить, что фары зажглись (а это — тестовое суждение). Тестирование нескольких компонентов называется интеграционным тестированием.
Подумайте о всех вещах, которые должны правильно работать, чтобы простая задача выдала корректный результат. Эти компоненты похожи на части вашего приложения: все те классы, функции, модули, что вы написали.
Главная сложность интеграционного тестирования возникает, когда интеграционный тест не дает правильный результат. Сложно оценить проблему, не имея возможности изолировать сломанную часть системы. Если фары не зажглись, возможно лампочки сломаны. Или может аккумулятор разряжен? А может проблема в генераторе? Или вообще сбой в компьютере машины?
Современные машины сами оповестят вас о поломке лампочек. Определяется это с помощью модульного теста.
Модульный тест (юнит-тест) — небольшой тест, проверяющий корректность работы отдельного компонента. Модульный тест помогает изолировать поломку и быстрее устранить ее.
Мы поговорили о двух видах тестов:
Значения правильные, поэтому в REPL ничего не будет выведено. Если результат sum() некорректный, будет выдана AssertionError с сообщением “Should be 6” (“Должно быть 6”). Проверим оператор утверждения еще раз, но теперь с некорректными значениями, чтобы получить AssertionError :
Вместо REPL, положите это в новый Python-файл с названием test_sum.py и выполните его снова:
Теперь у вас есть написанный тест-кейс (тестовый случай), утверждение и точка входа (командной строки). Теперь это можно выполнить в командной строке:
Вы видите успешный результат, “Everything passed” (“Все пройдено”).
sum() в Python принимает на вход любой итерируемый в качестве первого аргумента. Вы проверили список. Попробуем протестировать кортеж. Создадим новый файл с названием test_sum_2.py со следующим кодом:
Можно увидеть, как ошибка в коде вызывает ошибку в консоли с информацией, где она произошла, и каким был ожидаемый результат.
Такие тесты подойдут для простой проверки, но что если ошибки есть больше, чем в одном? На помощь приходят исполнители тестов (test runners). Исполнитель тестов — особое приложение, спроектированное для проведение тестов, проверки данных вывода и предоставления инструментов для отладки и диагностики тестов и приложений.
Выбор Исполнителя Тестов
Для Python доступно множество исполнителей тестов. Например, в стандартную библиотеку Python встроен unittest. В этом руководстве, будем использовать тест-кейсы и исполнители тестов unittest. Принципы работы unittest легко адаптируются для других фреймворков. Перечислим самые популярные исполнители тестов:
unittest встроен в стандартную библиотеку Python, начиная с версии 2.1. Вы наверняка столкнетесь с ним в коммерческих приложениях Python и проектах с открытым исходным кодом.
В unittest есть тестовый фреймворк и исполнитель тестов. При написании и исполнении тестов нужно соблюдать некоторые важные требования.
Чтобы превратить ранее написанный пример в тест-кейс unittest, необходимо:
Таким образом, вы выполнили два теста с помощью исполнителя тестов unittest.
Примечание: Если вы пишете тест-кейсы для Python 2 и 3 — будьте осторожны. В версиях Python 2.7 и ниже unittest называется unittest 2. При импорте из unittest вы получите разные версии с разными функциями в Python 2 и Python 3.
Чтобы узнать больше о unittest’ах почитайте unittest документацию.
Со временем, после написания сотни, а то и тысячи тестов для приложения, становится все сложнее понимать и использовать данные вывода unittest.
nose совместим со всеми тестами, написанными с unittest фреймворком, и может заменить его тестовый исполнитель. Разработка nose, как приложения с открытым исходным кодом, стала тормозиться, и был создан nose2. Если вы начинаете с нуля, рекомендуется использовать именно nose2.
Для начала работы с nose2 нужно установить его из PyPl и запустить в командной строке. nose2 попытается найти все тестовые скрипы с test*.py в названии и все тест-кейсы, унаследованные из unittest.TestCase в вашей текущей директории:
pytest поддерживает выполнение тест-кейсов unittest. Но настоящее преимущество pytest — его тест-кейсы. Тест-кейсы pytest — серия функций в Python-файле с test_ в начале названия.
Есть в нем и другие полезные функции:
Вы избавились от TestCase, использования классов и точек входа командной строки.
Больше информации можно найти на Сайте Документации Pytest.
Написание Первого Теста
Объединим все, что мы уже узнали, и вместо встроенной функции sum() протестируем простую реализацию с теми же требованиями.
Структура папок будет выглядеть так:
project/
│
└── my_sum/
└── __init__.py
При использовании __import__() вам не придется превращать папку проекта в пакет, и вы сможете указать имя файла. Это полезно, если имя файла конфликтует с названиями стандартных библиотек пакетов. Например, если math.py конфликтует с math модулем.
Как Структурировать Простой Тест
Перед написанием тестов, нужно решить несколько вопросов:
Код в этом примере:
Как Писать Утверждения
Последний шаг в написании теста — проверка соответствия выходных данных известным значениям. Это называют утверждением (assertion). Существует несколько общих рекомендаций по написанию утверждений:
Метод | Эквивалент |
---|---|
.assertEqual(a, b) | a == b |
.assertTrue(x) | bool(x) is True |
.assertFalse(x) | bool(x) is False |
.assertIs(a, b) | a is b |
.assertIsNone(x) | x is None |
.assertIn(a, b) | a in b |
.assertIsInstance(a, b) | isinstance(a, b) |
Писать тесты сложнее, чем просто смотреть на возвращаемое значение функции. Зачастую, выполнение кода меняет другие части окружения: атрибуты класса, файлы файловой системы, значения в базе данных. Это важная часть тестирования, которая называется побочные эффекты. Решите, тестируете ли вы побочный эффект до того, как включить его в список своих утверждений.
Если вы обнаружили, что в блоке кода, который вы хотите протестировать, много побочных эффектов, значит вы нарушаете Принцип Единственной Ответственности. Нарушение принципа единственной ответственности означает, что фрагмент кода делает слишком много вещей и требует рефакторинга. Следование принципу единственной ответственности — отличный способ проектирования кода, для которого не составит труда писать простые повторяемые модульные тесты, и, в конечном счете, создания надежных приложений.
Запуск Первого Теста
Вы создали первый тест и теперь нужно попробовать выполнить его. Понятно, что он будет пройден, но перед созданием более сложных тестов, нужно убедиться, что даже такие тесты выполняются успешно.
Запуск Исполнителей Тестов
Исполнитель тестов — приложение Python, которое выполняет тестовый код, проверяет утверждения и выдает результаты тестирования в консоли. В конец test.py добавьте этот небольшой фрагмент кода:
Другой способ — использовать командную строку unittest. Попробуем:
Мы исполнили один тест из test.py и вывели результаты в консоль. Многословный режим перечислил имена выполненных тестов и результаты каждого из них.
Вместо предоставления имени модуля, содержащего тесты, можно запросить авто-обнаружение при помощи следующего:
Эта команда будет искать в текущей директории файлы с test*.py в названии, чтобы протестировать их.
Понимание Результатов Тестирование
Это был очень простой пример, где все прошло успешно, поэтому попробуем понять выходные данные проваленного теста.
sum() должен принимать на вход другие списки числового типа, например дроби.
К началу кода в файле test.py добавьте выражение для импорта типа Fraction из модуля fractions стандартной библиотеки.
Теперь добавим тест с утверждением, ожидая некорректное значение. В нашем случае, ожидаем, что сумма ¼, ¼ и ⅖ будет равна 1:
В этих выходных данных вы видите следующее:
Запуск тестов из PyCharm
Если вы используете PyCharm IDE, то можете запустить unittest или pytest, выполнив следующие шаги:
Больше информации доступно на сайте PyCharm.
Запуск Тестов из Visual Studio Code
Если вы пользуетесь Microsoft Visual Studio Code IDE, поддержка unittest, nose и pytest уже встроена в плагин Python.
Если он у вас установлен, можно настроить конфигурацию тестов, открыв Command Palette по Ctrl+Shift+P и написав “Python test”. Вы увидите список вариантов:
Выберите Debug All Unit Tests, после чего VSCode отправит запрос для настройки тестового фреймворка. Кликните по шестеренке для выбора исполнителя тестов (unittest) и домашней директории (.).
По завершении настройки, вы увидите статус тестов в нижней части экрана и сможете быстро получить доступ к тестовым логам и повторно запустить тесты, кликнув по иконкам:
Видим, что тесты выполняются, но некоторые из них провалены.
В следующей части статьи мы рассмотрим тесты для фреймворков, таких как Django и Flask.
Ждём ваши вопросы и комментарии тут и, как всегда, можно зайти к Станиславу на день открытых дверей.