#python #pytest #decorator
Вопрос:
Я где-то читал о ТОМ, что вам следует проверять не декоратор, а функциональность обернутой функции. Тем не менее, может быть более короткий способ проверки того, назначен ли определенный декоратор нескольким функциям.
У меня есть этот декоратор:
def check_user(func): """Only allow admins to change the user_id in the annotated function. Use as decorator: @check_user """ @wraps(func) def wrapper(*args, **kwargs): ...
У меня есть несколько тестов для проверки самой функции декоратора, например:
def test_check_user(self): """Test the check user decorator if a non admin wants to overwrite the user.""" with pytest.raises(ValueError) as ex: @check_user def foo(login: str, userId: str): return True foo(login="Foo", userId="Bar") assert ex.value.args[0] == "Only admin users may overwrite the userId."
Теперь у меня есть около 20 конечных точек FastAPI, где я назначил этого декоратора. Я хочу избежать повторения одних и тех же тестов (см. Пример выше и другие тесты) для каждой функции. Так что что-то вроде этого было бы здорово:
@pytest.mark.parametrize("method", ["foo", "bar", "gaga", ....]) def test_decorated_methods(self, method): assert assigned(check_user, method) # or so
Ответ №1:
Вы должны иметь возможность изменять и параметризовать test_check_user, чтобы проверять одно и то же утверждение для каждой оформленной функции в одном тесте. Это лучше, чем просто проверка того, применяется ли декоратор, потому что он проверяет фактическое функциональное требование предотвращения изменения идентификатора пользователя лицами, не являющимися администраторами. Помните, что цель написания хороших тестов-защитить вас от вашего будущего «я». Хотя в настоящее время вы чувствуете, что можете определить функцию безопасности по присутствию этого декоратора, можете ли вы быть уверены, что этот вывод всегда будет верен до конца срока службы проекта? Лучше убедиться, что ваши функции безопасности действительно ведут себя так, как задумано.
@pytest.mark.parametrize("method,args,kwargs", [(my_func, ["Foo"], {}), (my_other_func, ["bar"], {})]) def test_cant_change_id_if_not_admin(func, args, kwargs): kwargs["userId"]="Bar" with pytest.raises(ValueError) as ex: func(*args, **kwargs) assert ex.value.args[0] == "Only admin users may overwrite the userId."
Комментарии:
1. Хорошая мысль и интересная альтернатива. Дай мне несколько дней, чтобы повозиться. Я перезвоню тебе. К вашему сведению, 1-я строка в вашем коде должна быть: @pytest.mark.parametrize(«функция, аргументы, параметры», [(myfunc, [«Foo»], {})]) Большое спасибо.
2. Ваш реальный тестовый код, вероятно, будет более сложным, возможно, вам потребуется имитировать любые используемые ресурсы, прежде чем возникнет исключение. К счастью, если вы правильно спроектируете свой декоратор, он, надеюсь, решит, следует ли вызывать исключение, прежде чем использовать много ресурсов, специфичных для функций. Проверки пользователя==администратора, вероятно, потребуется выполнять индивидуально, но это могут быть просто модифицированные версии простейшего теста happy path для каждой функции, которые, как мы надеемся, уже реализованы.
3. Работает как шарм. Большое спасибо.