Найти - Пользователи
Полная версия: Динамическое задание методов класса
Начало » Python для новичков » Динамическое задание методов класса
1
Borigor
Доброго времени суток, господа!

Возникло желание отрефакторить чужой код, для чего нужно сделать следующее.
Тест-раннер подгружает тест-класс, в его неймспейсе находит методы с вхождением определенной подстроки в имя метода, и все найденные методы исполняет.
Это есть данность, которую я трогать не могу (бо очень дорого обойдется рефакторинг).
Но в то же время мне не нравится организация работы этих методов, когда ими (методами) в цикле тестируется функциональность аналогичных сущностей с разными именами.
Примерно так:
class MyClass(TestClass):

def testFn(self, x):
seq1 = ['aaa', 'bbb', 'ccc', 'ddd', 'fff']
for s in seq1:
print x
Понятное дело, если метод фейлится на s=='ccc', то метод прекращает свою работу и до проверок функциональностей ‘ddd’ и ‘fff’ не доходит
Вот чтобы такого избежать, посетило меня желание переделать эти тестовые классы так, чтобы на основании имеющегося массива (неважно, статического или динамически подгружаемого при инициализации) динамически создавались необходимые методы, делающие одно и то же, но каждый со своим именем и работающий со своею тестируемой сущностью.
Вот что у меня получилось в результате экспериментов:
class MyClass():
seq1 = ['aaa', 'bbb', 'ccc', 'ddd', 'fff']

for s in seq1:
exec "def test%s(self): self.my_fn('%s')" % (s.capitalize(), s)

def my_fn(self, x):
print x


if __name__ == "__main__":
obj = MyClass()
for k in MyClass.__dict__:
if k.find('test') == 0:
m = getattr(obj, k)
m()
Надеюсь, что то же самое можно было бы реализовать элегантнее, но не нашел, как.
Прошу ваших мнений, предложений, конструктивной критики.
doza_and
А почему нельзя было заловить и обработать выскакивающие исключения?
Borigor
doza_and
А почему нельзя было заловить и обработать выскакивающие исключения?
Если бы можно было хэндлить исключения, я бы с этим не заморачивался.
Увы, это не разрешено.
Базовый фреймворк так построен, что при возникновении исключения метод обязательно должен зафейлиться.
Андрей Светлов
Все хуже. Нужно посмотреть unittest:TestCase.run и сделать по подобию.
Borigor
Андрей Светлов
Все хуже. Нужно посмотреть unittest:TestCase.run и сделать по подобию.
собственно, это оттуда и есть:
      m = getattr(obj, k)
m()
но суть именно в том как поэлегантнее задать эти методы.
или я неправильно уловил суть совета?
Андрей Светлов
Собственно говоря зачем лепить методы, да еще и через варварский exec?
Давайте вы показываете кусочек кода, а там посмотрим.
Имеющиеся — никуда не годятся.
Мы говорим о unittest? Откуда это следует?
Если ваш MyClass — тестовый контейнер, то почему он не наследует TestCase?
Как делается “проверка правильности”? Простой print выглядит неубедительно.
Borigor
Андрей Светлов
Собственно говоря зачем лепить методы, да еще и через варварский exec?
Давайте вы показываете кусочек кода, а там посмотрим.
Имеющиеся — никуда не годятся.
Мы говорим о unittest? Откуда это следует?
Если ваш MyClass — тестовый контейнер, то почему он не наследует TestCase?
Как делается “проверка правильности”? Простой print выглядит неубедительно.
Вроде же достаточно раскрыл подоплеку необходимости этого:
необходимо проверить все(!) функциональности, которые сейчас проверяются в цикле в одном методе.
Трогать фреймворк (да, на базе unittest'а), я тоже не вправе, т.к. код не мой, и никто мне добро на это не даст.
Поэтому не существенно, на мой взглгяд, unittest это или нет
Чаще всего список функциональностей получается динамически, запросом к базе, поэтому я не могу при имплементации тестов наплодить 10-15 оберток-тестовых методов, вызывающих один и тот же метод.
Вот и не нашлось другого пути, кроме как динамически генерировать методы.
А вот как это лучше сделать, в этом и состоит мой интерес.

Тестовых классов (и методов в них) очень много, и все разные.. суть методов - ассерты.
print я применил лишь для наглядной проверки работоспособности решения.
Андрей Светлов
Есть сферический конь с педальным приводом. Детали реализации не важны.
Как его улучшить?
Коня — не покажу, даже на полвзгляда. И не просите!
Вроде бы я достаточно раскрыл делали и прочие функциональные особенности?

Еще раз повторяю, если кто чего не понял.
Есть конь. Сферический. Всем хорош, но олени быстро устают. Приделал педали. Можно ли улучшить конструкцию?
Borigor
Андрей, я ценю Ваше чувство юмора.
Только почему бы нам на абстрагироваться от unittest'а, и не рассмотреть вопрос, как он поставлен.
Вот Вы упомянули “варварский exec”, видимо имея в виду наличие более тонкого/правильного подхода к реализации сабжа?
Был бы признателен, если бы поделились идеями.
Андрей Светлов
Привет от наших психов — вашим. И так вроде бы абстрагировались до полной сферичности.
Тем не менее — держите:
>>> class A(object):
... pass
...
... for name in 'abc':
... setattr(A, name, lambda self, name=name: name)
...
... a = A()
... print a.a()
... print a.b()
... print a.c()
a
b
c
>>>
This is a "lo-fi" version of our main content. To view the full version with more information, formatting and images, please click here.
Powered by DjangoBB