Динамический вызов метода из списка классов / объектов Python - PullRequest
0 голосов
/ 09 марта 2012

У меня есть X классов Python, которые все наследуют от одного и того же абстрактного базового класса, который ожидает, что дети реализуют единственный метод executeTest ()

Class TestCase:
   def executeTest():
   #do some logic for the test, then return if it passed or failed

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

Как я могу сделать это эффективно в Python? Нужно ли иметь отдельный XML-файл или файл схожего типа, в котором есть список всех отдельных имен классов, а затем использовать какую-то функцию загрузки классов внутри цикла for? Это мой первый ночной код на python, поэтому я даже не совсем уверен, какие методы или ключевые слова искать.

Ответы [ 3 ]

2 голосов
/ 09 марта 2012

Это мета-ответ - это означает, что я думаю, что вы должны подумать о том, как ваш проект вызывает тесты.

В Python есть хорошо разработанные способы написания тестов.[1] И есть также инструменты, которые собирают все доступные тесты и выполняют их (включая статистику, охват, вывод XML, ...).[2]

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

[1] http://docs.python.org/library/unittest.html
[2] http://readthedocs.org/docs/nose/en/latest/
0 голосов
/ 09 марта 2012

Я постараюсь сделать это так:

1) Сохраните свой абстрактный класс в test_case.py

class TestCase:
    def executeTest():
        #do some logic for the test, then return if it passed or failed

2) Сохраните все ваши дочерние классы в test_case_children.py

from test_case import TestCase
class Test_Case_1(TestCase):
    def executeTest():
        #overriden function

class Test_Case_2(TestCase):
    def executeTest():
        #overriden function

class Test_Case_3(TestCase):
    def executeTest():
        #overriden function

3) Сохранить основную функцию в main.py:

from test_case import TestCase
import test_case_children

def main():
    #grab the all the elements in the script 'test_case_children'
    items = test_case_children.__dict__

    #build list of all 'TestCase' sub-classes
    test_classes = [] 
    for (key, value) in items.items():
        try:
            # check whether the item is a sub-class of 'TestCase' class
            if TestCase.__subclasscheck__(value):
                test_classes.append(value)
        except TypeError: #if item is not of type 'TestCase', ignore it
            pass

    #run the tests
    for test_class in test_classes:
        test_runner = test_class()
        test_runner.executeTest()


# this will run main() method, only when script is directly executed 
# from shell or command prompt ...
if __name__ == "__main__":
    main()

4) Выполнить скрипт main.py:

$ python main.py

Примечание: Еще одна вещь, папка, в которой вы будете сохранять эти файлы, должна также содержать пустой файл __init__.py, чтобы сделать эту папку приложением Python (что-то вроде packages в Java или namespaces в C++). Если вы этого не сделаете, то, вероятно, эти операторы импорта не будут работать.

[ Обновление для запуска test_cases из разных файлов ]

1) Сохраните файлы в следующей иерархии:

<root>/
------>test_case/
---------------->__init__.py
---------------->main.py
---------------->test_case.py
---------------->test_case_children/
--------------------------------->__init__.py
--------------------------------->test_case_1.py
--------------------------------->test_case_2.py
--------------------------------->test_case_3.py

2) Сохраните свой абстрактный класс в test_case/test_case.py

class TestCase:
    def executeTest():
        #do some logic for the test, then return if it passed or failed

3) Сохранить подклассы так:

Файл: test_case/test_case_children/test_case_1.py

from test_case.test_case import TestCase
class Test_Case_1(TestCase):
    def executeTest():
        #overriden function

Файл: test_case/test_case_children/test_case_2.py

from test_case.test_case import TestCase
class Test_Case_2(TestCase):
    def executeTest():
        #overriden function

Файл: test_case/test_case_children/test_case_3.py

from test_case.test_case import TestCase
class Test_Case_3(TestCase):
    def executeTest():
        #overriden function

4) Сохранить основную функцию в main.py:

from test_case import TestCase
from test_case import test_case_children

def main():
    #grab the all the elements in the module 'test_case_children'
    items = test_case_children.__dict__

    #build list of all 'TestCase' sub-classes
    test_classes = []
    for (dict_key, dict_value) in items:
        #check whether the type of item's value is a module,
        # if its a module it's likely to contain a TestCase subclass...
        if str(type(dict_value)) == "<type 'module'>":
            for (key, value) in dict_value.items():
                try:
                    # check whether the item is a sub-class of 'TestCase' class
                    if TestCase.__subclasscheck__(value):
                        test_classes.append(value)
                except TypeError: #if item is not of type 'TestCase', ignore it
                    pass

    #run the tests
    for test_class in test_classes:
        test_runner = test_class()
        test_runner.executeTest()


# this will run main() method, only when script is directly executed 
# from shell or command prompt ...
if __name__ == "__main__":
    main()

5) Выполнить скрипт main.py:

$ cd test_case/
$ python main.py

Надеюсь, это сработает для вас.

0 голосов
/ 09 марта 2012

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

...