Рубрики
Без рубрики

INTRO для тестирования на основе собственности в Python

Автор оригинала: FreeCodeCapm Team.

Шаши Кумар Раджа

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

Статья собирается использовать Базовые Pтойские концепции объяснить тестирование на основе недвижимости. Я рекомендую вам Прочитайте эту статью Чтобы быстро почистить ваши питистые знания.

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

Каждый великий магический трюк состоит из трех частей или актов. Первая часть называется «залог». Маг показывает вам что-то обычное : колода открыток, птица или мужчина. Он показывает вам этот объект. Возможно, он просит вас осмотреть его, чтобы посмотреть, действительно ли это действительно реально, неизменно, нормально. Но конечно … это, вероятно, нет.

Часть 1: Пример на основе тестирования

Подход к примеру на основе тестирования имеет следующие шаги:

  • Учитывая тестовый вход я
  • При прохождении функции под тестом
  • должен вернуть выход О

Таким образом, в основном мы даем фиксированный ввод и ожидаю фиксированного вывода.

Чтобы понять эту концепцию в Условиях Лэймана:

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

Теперь, чтобы проверить эту машину, используя примерные тестирования, мы будем следовать ниже подхода:

  1. Возьмите синий сырой пластик ( Фиксированные тестовые данные )
  2. кормить пластик к машине
  3. Ожидайте, что пластиковый шарик синего цвета как вывод ( Исправленная тестовая вывод )

Давайте посмотрим на тот же подход в программном порядке.

Пререквизит: Убедитесь, что у вас есть Python (версия 2.7 или выше) и Pteest установлены.

Создайте структуру каталогов, как это:

- demo_tests/    - test_example.py

Мы напишем одну маленькую функцию сумма Внутренний файл test_example.py Отказ Это принимает два числа – Num1 и Num2 – в качестве параметров и возвращает добавление обоих чисел в качестве результата.

def sum(num1, num2):    """It returns sum of two numbers"""    return num1 + num2

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

import pytest
#make sure to start function name with testdef test_sum():    assert sum(1, 2) == 3

Здесь вы можете увидеть, что мы передаем два значения 1 и 2 и ожидая суммы вернуть 3 Отказ

Запустите тесты, пройдя в Demo_tests Папка, а затем работает следующую команду:

pytest test_example.py -v

Этот тест достаточно Чтобы проверить функциональность сумма функция?

Вы можете думать, конечно, нет. Мы напишем больше тестов, используя Pytest Carmetrize функция, которая будет выполнять это test_sum Функция для всех заданных значений.

import pytest
@pytest.mark.parametrize('num1, num2, expected',[(3,5,8),              (-2,-2,-4), (-1,5,4), (3,-5,-2), (0,5,5)])def test_sum(num1, num2, expected):        assert sum(num1, num2) == expected

Использование пяти тестов дало больше уверенности в функциональности. Все они проходят почувствовать себя блаженству.

Но Если вы посмотрите более внимательно, мы делаем то же самое, что мы сделали выше, но для большего количества ценностей. Мы до сих пор не охватываем несколько краев.

Итак, мы обнаружили первую болевую точку с этим методом тестирования:

Выпуск 1: тестовая исчерпываемость зависит от лица, написания теста

Они могут выбрать писать 5 или 50 или 500 тестовых случаев, но все же остаются не уверены, благополучно охватываем большинство, если не все, краевые чехлы.

Это приводит нас к нашей второй болевой точке:

Выпуск 2 – Неудивительные тесты из-за неясных/неоднозначных требований понимания

Когда нам сказали написать наши сумма Функция, какие конкретные детали были переданы?

Мы сказали нам:

  • Какой вклад наша функция должна ожидать?
  • Как наша функция должна вести себя в неожиданные входные сценарии?
  • Какой вывод наша функция должна вернуться?

Быть более точным, если вы считаете сумма Функция, которую мы написали выше:

  • мы знаем, если Num1 , Num2 должен быть int или плавать ? Могут ли они также быть отправлены как тип строка или любой другой тип данных?
  • Что такое Минимальный и Максимум Значение Num1 и Num2 что мы должны поддерживать?
  • Как функция должна вести себя, если мы получим null входы?
  • Должен ли вывод, возвращенный функцией суммы int или плавать или строка или любой другой тип данных?
  • В каких сценариях он должен отображать сообщения об ошибках?

Кроме того, худший сценарий Из вышеупомянутого тестового применения на написании подхода заключается в том, что эти тестовые случаи могут быть одурачивается, чтобы пройти миггическими функциями Отказ

Давайте переписать нашу сумма Функция таким образом, что ошибки введены, но тесты, которые мы написали до сих пор, все еще проходит.

def sum(num1, num2):    """Buggy logic"""       if num1 == 3 and num2 == 5:        return 8    elif num1 == -2 and num2  == -2 :        return -4    elif num1 == -1 and num2 == 5 :        return 4    elif num1 == 3 and num2 == -5:        return -2    elif num1 == 0 and num2 == 5:        return 5

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

Второй акт называется «поворотом». Маг что-то принимает обычное и делает его что-то необычное. Теперь вы ищете секрет … но вы не найдете его, потому что, конечно, вы на самом деле не смотрите. Вы на самом деле не хотите знать. Вы хотите быть обманутым.

Часть 2: тестирование на основе недвижимости

Введение и тестовые данные генерации

Испытание на основе недвижимости было впервые представлено QuickCheck Рамки в Haskell Отказ Согласно Fast-Check ‘ S Документация, которая является еще одной библиотекой тестирования на основе свойств

Чтобы понять это, давайте вернемся к нашему пластиковому шарику, генерирующему машину пример.

Подход тестирования на основе свойств будет:

  1. Возьмите огромный выбор пластмасс в качестве ввода ( все (x, y, ...) )
  2. Убедитесь, что все они окрашены ( Предварительное условие (x, y, ...) )
  3. Выход удовлетворяет следующему свойству ( Свойство (X, Y, ...) ) –
  • Вывод круглая/сферическая в форме
  • вывод окрашена
  • Цвет выхода является одним из цветов, присутствующих в цветовой зоне

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

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

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

Теперь давайте вернемся к нашей функции суммирования и проверьте его, используя подход на основе свойств.

Первый вопрос Что возникает вот: какой должен быть вход сумма функция?

Для объема этой статьи мы предположим, что любой Пара целые числа Из целочисленного набора является действительным входом.

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

Следующий вопрос Есть: как получить такие входные данные?

Ответ Для этого есть: библиотека тестирования на основе свойств предоставляет вам функцию генерировать огромный набор желаемых входных данных после предварительного условия.

В Python, Гипотеза это библиотека тестирования свойств, которая позволяет писать тесты вместе с Pтойными. Мы собираемся использовать эту библиотеку.

Вся документация гипотезы красиво написана и доступна ➡️ здесь И я рекомендую вам пройти через него.

Для установки гипотезы:

pip install hypothesis

И мы хороши, чтобы использовать гипотезу с Pтойцами.

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

from hypothesis import given
import hypothesis.strategies as st
import pytest
@given(st.integers(), st.integers())def test_sum(num1, num2):    assert sum(num1, num2) == num1 + num2
  • Первая строка просто импортирует Дано от гипотезы. @given Декоратор делает нашу тестовую функцию и превращает ее в параметризованный. При вызове, это запустит функцию тестирования по широкому диапазону согласованных данных. Это главная точка входа в гипотезу.
  • Вторая строка импортирует Стратегии от гипотезы. Стратегии предоставляют функцию генерировать тестовые данные Отказ Гипотеза предоставляет стратегии для большинства встроенных типов с аргументами для ограничения или настройки выхода. Кроме того, стратегии более высокого порядка могут быть составлены для создания более сложных типов.
  • Вы можете генерировать любую смесь следующих вещей, использующих стратегии:
'nothing','just', 'one_of','none','choices', 'streaming','booleans', 'integers', 'floats', 'complex_numbers', 'fractions','decimals','characters', 'text', 'from_regex', 'binary', 'uuids','tuples', 'lists', 'sets', 'frozensets', 'iterables','dictionaries', 'fixed_dictionaries','sampled_from', 'permutations','datetimes', 'dates', 'times', 'timedeltas','builds','randoms', 'random_module','recursive', 'composite','shared', 'runner', 'data','deferred','from_type', 'register_type_strategy', 'emails'
  • Здесь мы сгенерировали целые числа () Установите использование стратегий и передавали его на @given Отказ
  • Итак, наш test_sum Функция должна работать для всех итераций данного ввода.

Давайте запустим и увидим результат.

Возможно, вы думаете, я не вижу никакой разницы здесь. Что такое особенное в этом беге?

Ну, чтобы увидеть волшебную разницу, нам нужно запустить наш тест, установив Verbose вариант. Не путайте эту многословущую с -V вариант pteest.

from hypothesis import given, settings, Verbosity
import hypothesis.strategies as stimport pytest
@settings(verbosity=Verbosity.verbose)@given(st.integers(), st.integers())def test_sum(num1, num2):    assert sum(num1, num2) == num1 + num2

Настройки Позволяет настроить тестовое поведение по умолчанию по поведению гипотезы.

Теперь давайте повторно запустите тесты. Также включать -s На этот раз для захвата вывода потока в Pтойте.

pytest test_example.py -v -s

Посмотрите на огромное количество генерируемых и бегите. Вы можете найти все виды случаев здесь, таких как 0, большие числа и отрицательные числа.

Возможно, вы думаете, это впечатляет, но я не могу найти мою любимую пару тестовых корпусов (1,2) здесь. Что, если я хочу, чтобы бежать?

Ну, не бойся, гипотеза позволяет вам запускать данный набор тестовых случаев каждый раз, если вы хотите, используя @ Пример декоратор.

from hypothesis import given, settings, Verbosity, example
import hypothesis.strategies as stimport pytest
@settings(verbosity=Verbosity.verbose)@given(st.integers(), st.integers())@example(1, 2)def test_sum(num1, num2):    assert sum(num1, num2) == num1 + num2

Кроме того, обратите внимание, что каждый запуск будет всегда Создайте новый перемешиваемый тестовый случай, следуя стратегии генерации тестов, таким образом, что рандогизируйте тестовый прогон.

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

Думать трудно придумать свойства для тестирования

Пока что мы увидели одну магию тестирования на основе недвижимости, которое генерирует желаемые тестовые данные на лету.

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

1 + 0 = 10 + 1 = 15 + 0 = 5-3 + 0 = -38.5 + 0 = 8.5

Ну, это интересно. Похоже, добавляя 0 до количества результатов в том же номере, что и сумма. Это называется Свойство идентичности добавления.

Давайте посмотрим еще один:

2 + 3 = 53 + 2 = 5
5 + (-2) = 3-2 + 5 = 3

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

Есть еще один, но я хочу, чтобы вы придумали это.

Теперь мы повторем напишите наши test_sum Чтобы проверить эти свойства:

from hypothesis import given, settings, Verbosity
import hypothesis.strategies as stimport pytest
@settings(verbosity=Verbosity.verbose)@given(st.integers(), st.integers())def test_sum(num1, num2):    assert sum(num1, num2) == num1 + num2
    # Test Identity property    assert sum(num1, 0) = num1     #Test Commutative property      assert sum(num1, num2) == sum(num2, num1)

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

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

Вы можете увидеть, что он поймал ошибку. Фальсифицирующий пример:,). Это просто означает, что наша ожидаемая недвижимость не провела истина для этих пар испытательных случаев, таким образом, сбой.

Но вы еще не будете хлопать. Потому что что-то исчезнет недостаточно; Вы должны вернуть его обратно. Вот почему каждый волшебный трюк имеет третий акт, самая трудная часть, часть, которую мы называем «Престиж».

Часть 3: сокращение сбоев

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

Чтобы продемонстрировать эту функцию, давайте добавим еще одну недвижимость нашему test_sum Функция, которая говорит Num1 должно быть меньше или равно 30

from hypothesis import given, settings, Verbosity
import hypothesis.strategies as stimport pytest
@settings(verbosity=Verbosity.verbose)@given(st.integers(), st.integers())def test_sum(num1, num2):    assert sum(num1, num2) == num1 + num2
    # Test Identity property    assert sum(num1, 0) = num1     #Test Commutative property      assert sum(num1, num2) == sum(num2, num1)    assert num1 <= 30

После запуска этого теста вы получите интересный выходной журнал на терминале здесь:

collected 1 item
test_example.py::test_sum Trying example: test_sum(num1=0, num2=-1)Trying example: test_sum(num1=0, num2=-1)Trying example: test_sum(num1=0, num2=-29696)Trying example: test_sum(num1=0, num2=0)Trying example: test_sum(num1=-1763, num2=47)Trying example: test_sum(num1=6, num2=1561)Trying example: test_sum(num1=-24900, num2=-29635)Trying example: test_sum(num1=-13783, num2=-20393)
#Till now all test cases passed but the next one will fail
Trying example: test_sum(num1=20251, num2=-10886)assert num1 <= 30AssertionError: assert 20251 <= 30
#Now the shrinking feature kicks in and it will try to find the simplest value for which the test still fails
Trying example: test_sum(num1=0, num2=-2)Trying example: test_sum(num1=0, num2=-1022)Trying example: test_sum(num1=-165, num2=-29724)Trying example: test_sum(num1=-14373, num2=-29724)Trying example: test_sum(num1=-8421504, num2=-8421376)Trying example: test_sum(num1=155, num2=-10886)assert num1 <= 30AssertionError: assert 155 <= 30
# So far it has narrowed it down to 155
Trying example: test_sum(num1=0, num2=0)Trying example: test_sum(num1=0, num2=0)Trying example: test_sum(num1=64, num2=0)assert num1 <= 30AssertionError: assert 64 <= 30
# Down to 64
Trying example: test_sum(num1=-30, num2=0)Trying example: test_sum(num1=0, num2=0)Trying example: test_sum(num1=0, num2=0)Trying example: test_sum(num1=31, num2=0)
# Down to 31
Trying example: test_sum(num1=-30, num2=0)Falsifying example: test_sum(num1=31, num2=0)FAILED
# And it finally concludes (num1=31, num2=0) is the simplest test data for which our property doesn't hold true.

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

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

Вы можете найти весь код, используемый здесь, в моем? G ITTUB REPO.

Если вам понравилось контент, покажет некоторые ❤️