Введение
Практически во всех областях продукты тщательно тестируются перед выпуском на рынок, чтобы гарантировать их качество и работоспособность.
Медицина, косметические средства, транспортные средства, телефоны, ноутбуки – все это проверено, чтобы гарантировать, что они поддерживают определенный уровень качества, который был обещан потребителю. Учитывая влияние и охват программного обеспечения в нашей повседневной жизни, важно тщательно протестировать наше программное обеспечение, прежде чем выпускать его нашим пользователям, чтобы избежать проблем, возникающих при его использовании.
Существуют различные способы и методы тестирования нашего программного обеспечения, и в этой статье мы сосредоточимся на тестировании наших программ на Python с использованием Модульный тест фреймворк.
Модульное тестирование против других форм тестирования
Существуют различные способы тестирования программного обеспечения, которые в основном сгруппированы в функциональная а также нефункциональные тестирование.
- Нефункциональное тестирование: Предназначен для проверки и проверки нефункциональных аспектов программного обеспечения, таких как надежность, безопасность, доступность и масштабируемость. Примеры нефункционального тестирования включают нагрузочное тестирование а также нагрузочное тестирование,
- Функциональное тестирование: Включает тестирование нашего программного обеспечения на соответствие функциональным требованиям, чтобы убедиться, что оно обеспечивает требуемую функциональность. Например, мы можем проверить, отправляет ли наша торговая платформа электронные письма пользователям после размещения их заказов, моделируя этот сценарий и проверяя электронную почту.
Модульное тестирование подпадает под функциональное тестирование вместе с интеграционное тестирование а также регрессионное тестирование,
Модульное тестирование относится к методу тестирования, при котором программное обеспечение разбивается на различные компоненты (блоки), и каждый блок тестируется функционально и изолированно от других блоков или модулей.
Под единицей здесь понимается самая маленькая часть системы, которая выполняет одну функцию и является тестируемой. Целью модульного тестирования является проверка того, что каждый компонент системы работает так, как ожидается, что, в свою очередь, подтверждает, что вся система соответствует и выполняет функциональные требования.
Модульное тестирование обычно выполняется перед интеграционным тестированием, поскольку для того, чтобы убедиться, что части системы работают хорошо вместе, мы должны сначала убедиться, что они работают, как и ожидалось, индивидуально. Это также обычно выполняется разработчиками, создающими отдельные компоненты в процессе разработки.
Преимущества модульного тестирования
Модульное тестирование выгодно тем, что оно исправляет ошибки и проблемы на ранних этапах процесса разработки и в конечном итоге ускоряет его.
Стоимость исправления ошибок, выявленных в ходе модульного тестирования, также является низкой по сравнению с исправлением их во время интеграционного тестирования или в процессе производства.
Модульные тесты также служат документацией проекта, определяя, что делает каждая часть системы посредством хорошо написанных и документированных тестов. При рефакторинге системы или добавлении функций модульные тесты помогают защититься от изменений, которые нарушают существующие функции.
Unittest Framework
Вдохновленный Среда тестирования JUnit для Java, unittest
это среда тестирования для программ на Python, которая поставляется вместе с дистрибутивом Python начиная с Python 2.1. Иногда его называют PyUnit, Инфраструктура поддерживает автоматизацию и объединение тестов, а также общий код настройки и завершения их работы.
Это достигается благодаря многим следующим концепциям:
- Тестовый прибор: Определяет подготовку, необходимую для выполнения тестов, и любые действия, которые необходимо выполнить после завершения теста. Приспособления могут включать в себя настройку базы данных и подключение, создание временных файлов или каталогов, а также последующую очистку или удаление файлов после завершения теста.
- Прецедент: Относится к отдельному тесту, который проверяет конкретный ответ в данном сценарии с конкретными входными данными.
- Тестирование: Представляет совокупность тестовых случаев, которые связаны и должны выполняться вместе.
- Тест бегун: Координирует выполнение тестов и предоставляет результаты процесса тестирования пользователю через графический интерфейс пользователя, терминал или отчет, записанный в файл.
unittest
это не единственная среда тестирования для Python, другие включают Pytest, Robot Framework, Салат для BDD и Behave Framework,
Если вам интересно больше узнать о Тестовая разработка в Python с PyTestМы вас покроем!
Unittest Framework в действии
Мы собираемся исследовать unittest
фреймворк путем создания простого приложения калькулятора и написания тестов, чтобы убедиться, что оно работает как положено Мы будем использовать Разработка через тестирование процесс, начиная с тестов, затем реализуя функциональность, чтобы тесты прошли.
Хотя это хорошая практика для разработки нашего приложения Python в виртуальной среде, для этого примера это не будет обязательным, поскольку unittest
поставляется с дистрибутивом Python, и нам не понадобятся никакие другие внешние пакеты для сборки нашего калькулятора.
Наш калькулятор будет выполнять простые операции сложения, вычитания, умножения и деления между двумя целыми числами. Эти требования будут определять наши функциональные тесты с использованием unittest
фреймворк.
Мы протестируем четыре операции, поддерживаемые нашим калькулятором, отдельно и запишем тесты для каждой в отдельном наборе тестов, поскольку ожидается, что тесты конкретной операции будут выполняться вместе. Наши тестовые наборы будут размещены в одном файле, а наш калькулятор – в отдельном файле.
Наш калькулятор будет SimpleCalculator
класс с функциями для обработки четырех ожидаемых от него операций. Давайте начнем тестирование, написав тесты для операции сложения в нашем test_simple_calculator.py
:
import unittest
from simple_calculator import SimpleCalculator
class AdditionTestSuite(unittest.TestCase):
def setUp(self):
""" Executed before every test case """
self.calculator = SimpleCalculator()
def tearDown(self):
""" Executed after every test case """
print("ntearDown executing after the test case. Result:")
def test_addition_two_integers(self):
result = self.calculator.sum(5, 6)
self.assertEqual(result, 11)
def test_addition_integer_string(self):
result = self.calculator.sum(5, "6")
self.assertEqual(result, "ERROR")
def test_addition_negative_integers(self):
result = self.calculator.sum(-5, -6)
self.assertEqual(result, -11)
self.assertNotEqual(result, 11)
# Execute all the tests when the file is executed
if __name__ == "__main__":
unittest.main()
Начнем с импорта unittest
модуль и создание набора тестов (AdditionTestSuite
) для операции сложения.
В нем мы создаем setUp()
метод, который называется до каждый тестовый случай, чтобы создать наш SimpleCalculator
объект, который будет использоваться для выполнения расчетов.
tearDown()
метод выполнен после каждый тестовый случай, и так как в данный момент мы не особо используем его, мы просто используем его для распечатки результатов каждого теста.
Функции test_addition_two_integers()
, test_addition_integer_string()
а также test_addition_negative_integers()
наши тесты Ожидается, что калькулятор добавит два положительных или отрицательных целых числа и вернет сумму. Когда мы представляем целое число и строку, наш калькулятор должен возвращать ошибку.
assertEqual()
а также assertNotEqual()
это функции, которые используются для проверки результатов нашего калькулятора. assertEqual()
Функция проверяет, равны ли два предоставленных значения, в нашем случае мы ожидаем сумму 5
а также 6
быть 11
, поэтому мы сравним это со значением, возвращаемым нашим калькулятором.
Если два значения равны, тест пройден. Другие функции утверждения, предлагаемые unittest
включают:
assertTrue(a)
: Проверяет, является ли предоставленное выражениеtrue
assertGreater(a, b)
: Проверяет лиa
больше, чемb
assertNotIn(a, b)
: Проверяет лиa
вb
assertLessEqual(a, b)
: Проверяет лиa
меньше или равноb
- так далее…
Список этих утверждений можно найти в этот шпаргалка,
Когда мы выполняем тестовый файл, это вывод:
$ python3 test_simple_calulator.py
tearDown executing after the test case. Result:
E
tearDown executing after the test case. Result:
E
tearDown executing after the test case. Result:
E
======================================================================
ERROR: test_addition_integer_string (__main__.AdditionTestSuite)
----------------------------------------------------------------------
Traceback (most recent call last):
File "test_simple_calulator.py", line 22, in test_addition_integer_string
result = self.calculator.sum(5, "6")
AttributeError: 'SimpleCalculator' object has no attribute 'sum'
======================================================================
ERROR: test_addition_negative_integers (__main__.AdditionTestSuite)
----------------------------------------------------------------------
Traceback (most recent call last):
File "test_simple_calulator.py", line 26, in test_addition_negative_integers
result = self.calculator.sum(-5, -6)
AttributeError: 'SimpleCalculator' object has no attribute 'sum'
======================================================================
ERROR: test_addition_two_integers (__main__.AdditionTestSuite)
----------------------------------------------------------------------
Traceback (most recent call last):
File "test_simple_calulator.py", line 18, in test_addition_two_integers
result = self.calculator.sum(5, 6)
AttributeError: 'SimpleCalculator' object has no attribute 'sum'
----------------------------------------------------------------------
Ran 3 tests in 0.001s
FAILED (errors=3)
В верхней части вывода мы можем увидеть выполнение tearDown()
Функция через печать сообщения, которое мы указали. Далее следует письмо E
и сообщения об ошибках, возникающих при выполнении наших тестов.
Есть три возможных результата теста: он может пройти, провалиться или столкнуться с ошибкой. unittest
Framework указывает три сценария с помощью:
- Полный стоп (
.
): Указывает на прохождение теста - Буква "F": Указывает на провал теста
- Буква "Е": Указывает на ошибку, возникшую во время выполнения теста
В нашем случае мы видим письмо E
Это означает, что наши тесты столкнулись с ошибками, возникшими при выполнении наших тестов. Мы получаем ошибки, потому что мы еще не реализовали addition
Функциональность нашего калькулятора:
class SimpleCalculator:
def sum(self, a, b):
""" Function to add two integers """
return a + b
Наш калькулятор теперь готов добавить два числа, но чтобы быть уверенным, что он будет работать так, как ожидалось, давайте удалим tearDown()
функционировать из наших тестов и запустить наши тесты еще раз:
$ python3 test_simple_calulator.py
E..
======================================================================
ERROR: test_addition_integer_string (__main__.AdditionTestSuite)
----------------------------------------------------------------------
Traceback (most recent call last):
File "test_simple_calulator.py", line 22, in test_addition_integer_string
result = self.calculator.sum(5, "6")
File "/Users/robley/Desktop/code/python/unittest_demo/src/simple_calculator.py", line 7, in sum
return a + b
TypeError: unsupported operand type(s) for +: 'int' and 'str'
----------------------------------------------------------------------
Ran 3 tests in 0.002s
FAILED (errors=1)
Наши ошибки сократились с 3 до 1 раз. Резюме отчета в первой строке E..
указывает, что один тест привел к ошибке и не смог завершить выполнение, а остальные два пройдены. Чтобы выполнить первый тестовый тест, мы должны реорганизовать нашу функцию суммы следующим образом:
def sum(self, a, b):
if isinstance(a, int) and isinstance(b, int):
return a + b
Когда мы запустим наши тесты еще раз:
$ python3 test_simple_calulator.py
F..
======================================================================
FAIL: test_addition_integer_string (__main__.AdditionTestSuite)
----------------------------------------------------------------------
Traceback (most recent call last):
File "test_simple_calulator.py", line 23, in test_addition_integer_string
self.assertEqual(result, "ERROR")
AssertionError: None != 'ERROR'
----------------------------------------------------------------------
Ran 3 tests in 0.001s
FAILED (failures=1)
На этот раз наша функция sum выполняется до завершения, но наш тест не пройден. Это потому, что мы не возвращали никакого значения, когда один из входных данных не является целым числом. Наше утверждение сравнивает None
в ERROR
и поскольку они не равны, тест не пройден. Чтобы пройти тест, мы должны вернуть ошибку в нашем sum()
функция:
def sum(self, a, b):
if isinstance(a, int) and isinstance(b, int):
return a + b
else:
return "ERROR"
И когда мы запускаем наши тесты:
$ python3 test_simple_calulator.py
...
----------------------------------------------------------------------
Ran 3 tests in 0.000s
OK
Все наши тесты пройдены сейчас, и мы получаем 3 точки остановки, чтобы показать, что все 3 теста на функциональность добавления пройдены. Наборы тестов вычитания, умножения и деления также реализованы аналогичным образом.
Мы также можем проверить, возникло ли исключение. Например, когда число делится на ноль, ZeroDivisionError
исключение поднято. В нашем DivisionTestSuite
Мы можем подтвердить, было ли возбуждено исключение:
class DivisionTestSuite(unittest.TestCase):
def setUp(self):
""" Executed before every test case """
self.calculator = SimpleCalculator()
def test_divide_by_zero_exception(self):
with self.assertRaises(ZeroDivisionError):
self.calculator.divide(10, 0)
test_divide_by_zero_exception()
выполнит divide(10, 0)
Функция нашего калькулятора и подтвердит, что исключение действительно было поднято. Мы можем выполнить DivisionTestSuite
в отдельности, следующим образом:
$ python3 -m unittest test_simple_calulator.DivisionTestSuite.test_divide_by_zero_exception
.
----------------------------------------------------------------------
Ran 1 test in 0.000s
OK
Полный набор тестов функциональности деления можно найти в приведенной ниже сущности вместе с наборами тестов для функций умножения и вычитания.
Вывод
В этой статье мы исследовали unittest
фреймворк и определены ситуации, в которых он используется при разработке программ на Python. unittest
рамки, также известные как PyUnit, поставляется с дистрибутивом Python по умолчанию, в отличие от других сред тестирования. TDD-способом мы написали тесты для простого калькулятора, выполнили тесты и затем реализовали функциональность, чтобы тесты прошли.
unittest
Framework предоставил функциональность для создания и группировки тестовых случаев и проверки выходных данных нашего калькулятора в сравнении с ожидаемыми выходными данными, чтобы убедиться, что он работает должным образом.
Полный калькулятор и наборы тестов можно найти здесь в этом Gist на GitHub,
0 Comments