Я пишу несколько тестов для библиотеки, используя pytest
.Я хочу попробовать несколько тестовых случаев для каждой функции, предоставляемой библиотекой, поэтому мне было удобно сгруппировать тесты для каждого метода в классе.Все функции, которые я хочу протестировать, имеют одинаковую сигнатуру и возвращают одинаковые результаты, поэтому я хотел бы использовать вспомогательный метод, определенный в суперклассе, чтобы сделать некоторые утверждения относительно результатов.Упрощенная версия будет работать так:
class MyTestCase:
function_under_test: Optional[Callable[[str], Any]] = None
def assert_something(self, input_str: str, expected_result: Any) -> None:
if self.function_under_test is None:
raise AssertionError(
"To use this helper method, you must set the function_under_test"
"class variable within your test class to the function to be called.")
result = self.function_under_test.__func__(input_str)
assert result == expected_result
# various other assertions on result...
class FunctionATest(MyTestCase):
function_under_test = mymodule.myfunction
def test_whatever(self):
self.assert_something("foo bar baz")
В assert_something
. Необходимо вызвать __func__()
для функции, поскольку назначение функции атрибуту класса делает ее связанным методом этого класса -в противном случае self
будет передан в качестве первого аргумента функции внешней библиотеки, где это не имеет никакого смысла.
Этот код работает как задумано.Однако это приводит к ошибке MyPy:
"Callable[[str], Any]" has no attribute "__func__"
Исходя из моей аннотации, это правильно, что это не безопасная операция: произвольный Callable может не иметь атрибута __func__
.Однако я не могу найти аннотацию типа, которая указала бы, что переменная function_under_test
ссылается на метод и, следовательно, всегда будет иметь __func__
.Я пропускаю один или есть другой способ настроить мои аннотации или доступы, чтобы заставить это работать с проверкой типов?
Конечно, есть много других способов, которыми я мог бы обойти это, некоторые из которых могли бы дажебыть чище (использовать тип Any
, пропустить проверку типов, использовать закрытый метод для возврата тестируемой функции, а не делать ее переменной класса, сделать вспомогательный метод функцией и т. д.).Меня больше интересует, есть ли аннотация или другой трюк с Mypy, который заставил бы этот код работать.