Тестирование Python приложений с помощью hypothesis
Тестирование с использованием наработанных экспертами входных воздействий
При написании unit-тестов бывает трудно подобрать тестовые значения. Каждый из нас начинает идти по одним и тем же граблям, набирая свою базу “волшебных значений”, которые скорее всего уронят ваш код и найдут в нем баг.
Не так давно был моден тренд на генерацию случайных значенийв качестве входных значений.
Это и в самом деле очень эффективный способ проверять систему в целом.
Но это не очень удобно, потому что либо приводит к непредсказумости тестов - при одном прогоне они падают, при другом - нет. Либо требуют где-то поддерживать базу тест-кейсов, куда инструментарий для таких тестов будет складывать упавшие кейсы, чтобы их не потерять. Что в условиях распределенных CI со множеством агентов не очень просто организовать. Да еще в условиях когда мы хотим локально запускать unit-тесты, еще до отправки на CI.
К тому же, чтобы случайно попасть на болевые точки надо прогнать большое число тестов со случайными данными - это по сути вариант Теоремы о бесконечных обезьянах.
Для Python существует замечательный инструмент, который с одной стороны не имеет проблемы “мигающих тестов”, а с другой уже собрал за нас базу “проблемных” входных параметров.
class Employee:
def __init__(self, salary):
self.salary = salary
def give_a_raise(self, increase):
self.salary += increase
from hypothesis import given
from hypothesis import strategies as st
money_strategy = st.floats(min_value=1, max_value=1000000, allow_nan=False, allow_infinity=False)
@given(money_strategy, money_strategy, money_strategy)
def test_bonus_distribution(salary1, salary2, bonus_fund):
e1 = Employee(salary1)
e2 = Employee(salary2)
increase1 = bonus_fund / 2
increase2 = bonus_fund - increase1
e1.give_a_raise(increase1)
e2.give_a_raise(increase2)
money_spent = e1.salary - salary1 + e2.salary - salary2
assert bonus_fund == money_spent
test_finance.py F
test_finance.py:15 (test_bonus_distribution)
1.0000000000000002 != 1.0
Expected :1.0
Actual :1.0000000000000002
Конечно, я привел первый пришедший в голову пример как нельзя работать с деньгами - их никогда нельзя представлять в приложении как float. Бухгалтерии важна каждая копейка, и они почему-то предпочитают работать с деньгами в десятичном представлении. Что плохо сочетается с хранением в компьютере в двоичном виде, который по определению не может точно представить любое произвольное дробное.
С другой стороны, пример замечателен тем, что показывает, что перед нами не просто test framework, а экспертная БД, которая зачастую покажет, какой код неверен на уровне архитектуры.