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

1656591862 vvedenie v modulnoe testirovanie v python

Вы только что закончили писать фрагмент кода, и вам интересно, что делать. Вы подадите запрос на выписку и попросите своих товарищей по команде просмотреть код? Или вы будете тестировать код вручную?

Вам следует сделать обе эти вещи, но с дополнительным шагом: вам нужно провести модульное тестирование кода, чтобы убедиться, что код работает должным образом.

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

Лучший способ понять тестирование – это сделать его практичным. Для этого в файле с именем name_function.py я напишу простую функцию, которая берет имя и фамилию и возвращает полное имя:

#Generate a formatted full name
def formatted_name(first_name, last_name):
   full_name = first_name + ' ' + last_name
   return full_name.title()

Функция formatted_name() берет имя и фамилию и объединяет их с пробелом между ними для создания полного имени. Затем он пишет первую букву каждого слова с прописной. Чтобы проверить, работает ли этот код, необходимо написать какой-то код, использующий эту функцию. В names.py я напишу простой код, который позволит пользователям вводить свое имя и фамилию:

from name_function import formatted_name

print("Please enter the first and last names or enter x to E[x]it.")

while True:
   first_name = input("Please enter the first name: ")
   if first_name == "x":
       print("Good bye.")
       break

   last_name = input("Please enter the last name: ")
   if last_name == "x":
       print("Good bye.")
       break

   result = formatted_name(first_name, last_name)
   print("Formatted name is: " + result + ".")

Этот код импортирует formatted_name() из name_function.py и при работе позволяет пользователю вводить ряд имен и фамилий и показывает отформатированные полные имена.

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

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

Вот типичный сценарий написания тестов:

Сначала нужно создать тестовый файл. Затем импортируйте модуль unittest, определите тестовый класс, который наследуется от unittest.TestCase, и, наконец, напишите ряд методов для проверки всех случаев поведения вашей функции.

Под следующим кодом есть пояснение строка за строкой:

import unittest
from name_function import formatted_name

class NamesTestCase(unittest.TestCase):

   def test_first_last_name(self):
       result = formatted_name("pete", "seeger")
       self.assertEqual(result, "Pete Seeger")

Сначала вам нужно импортировать модульный тест и функцию, которую вы хотите проверить formatted_name() . Затем вы создаете класс, например NamesTestCase, который будет содержать тесты для функции formatted_name(). Этот класс наследуется от класса unittest.TestCase.

NamesTestCase содержит один метод, проверяющий одну часть formatted_name() . Этот метод можно вызвать test_first_last_name().

Помните, что каждый метод, начинающийся с test_, будет запущен автоматически, когда вы запустите test_name_function.py.

В тестовом методе test_first_last_name() вы вызываете функцию, которую хотите проверить, и сохраняете возвращаемое значение. В этом примере мы будем вызывать formatted_name() с аргументами pete и seeger и сохраним результат в результирующую переменную.

В последней строке мы будем использовать метод assert. Метод assert проверяет, что полученный вами результат соответствует результату, который вы ожидали получить. И в этом случае мы знаем, что функция formatted_name() вернет полное имя с прописными первыми буквами, поэтому ожидаем результат «Пит Сигер». Чтобы проверить это, используется метод assertEqual() unittest.

self.assertEqual(result, “Pete Seeger”)

Эта строка в основном означает: сравните значение результирующей переменной с «Питом Сигером», и если они равны, это нормально, но если их нет, сообщите мне.

При выполнении test_name_function.py ожидается, что вы получите OK, что означает, что тест пройден.

Ran 1 test in 0.001s

OK

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

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

#Generate a formatted full name including a middle name
def formatted_name(first_name, last_name, middle_name):
   full_name = first_name + ' ' + middle_name + ' ' + last_name
   return full_name.title()

Эта версия formatted_name() будет работать для людей с отчеством, но когда вы протестуете, вы увидите, что функция не работает для людей, не имеющих отчество.

Итак, когда вы запустите test_name_function.py, вы получите результат, который выглядит примерно так:

Error
Traceback (most recent call last):

File “test_name_function.py”, line 7, in test_first_last_name
    result = formatted_name(“pete”, “seeger”)

TypeError: formatted_name() missing 1 required positional argument: ‘middle_name’

Ran 1 test in 0.002s

FAILED (errors=1)

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

  • Первым элементом в выводе является ошибка, сообщающая вам, что по крайней мере один тест в тестовом случае привел к ошибке.
  • Далее вы увидите файл и метод, при котором произошла ошибка.
  • После этого вы увидите строку, в которой произошла ошибка.
  • И что это за ошибка, в данном случае нам не хватает одного аргумента «middle_name».
  • Вы также увидите количество запущенных тестов, время, необходимое для завершения тестов, и текстовое сообщение, представляющее статус тестов с количеством возникших ошибок.

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

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

В этом примере наша функция formatted_name() сначала требовала двух параметров, а теперь, когда она была переписана, она требует одного дополнительного: отчества. Добавление второго имени к нашей функции нарушило желаемое поведение. Поскольку идея состоит в том, чтобы не вносить изменения в тесты, лучшее решение сделать отчество необязательным.

После того, как мы это сделаем, идея состоит в том, чтобы тесты проходили, когда используются имя и фамилию, например «Пит Сигер», а также когда используются имя, фамилию и отчество, например «Реймонд Ред Реддингтон» . Давайте еще раз изменим код formatted_name():

#Generate a formatted full name including a middle name
def formatted_name(first_name, last_name, middle_name=""):
   if len(middle_name) > 0:
       full_name = first_name + ' ' + middle_name + ' ' + last_name
   else:
       full_name = first_name + ' ' + last_name
   return full_name.title()

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

И чтобы убедиться, что он все еще работает с «Питом Сигером», запустите тест снова:

Ran 1 test in 0.001s

OK

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

Напишите новый метод в класс NamesTestCase, который будет тестировать отчество:

import unittest
from name_function import formatted_name

class NamesTestCase(unittest.TestCase):

    def test_first_last_name(self):
        result = formatted_name("pete", "seeger")
        self.assertEqual(result, "Pete Seeger")

    def test_first_last_middle_name(self):
        result = formatted_name("raymond", "reddington", "red")
        self.assertEqual(result, "Raymond Red Reddington")

После выполнения теста оба теста должны пройти:

Ran 2 tests in 0.001s

OK

Bra gjort!
Молодцы!

Вы написали свои тесты, чтобы проверить, работает ли функция, используя имена с отчеством или без. Следите за обновлениями в части 2, где я расскажу больше о тестировании на Python.

Спасибо, что читаете! Просмотрите больше таких статей в моем профиле freeCodeCamp: и другие интересные вещи, которые я создаю на своей странице GitHub:

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *