user1258538
user1258538

Reputation: 1

Dynamically call a method from a list of Python classes/objects

I have X number of python classes that all inherit from the same abstract base class, which expects children to implement a single method called executeTest()

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

In my main program I need to load an instance of each class that inherits this base class one at a time, call executeTest(), and record the result into some sort of collection for later use. The number of classes that implement TestCase will continue to grow over time, as people think up new tests to write.

How can I do this efficiently in python? Do I need to have a separate XML or similar type file which has a list of all individual class names, and then use some sort of class loading function inside a for loop? This is my first night coding in python so I'm not even really sure what techniques or keywords to search for.

Upvotes: 0

Views: 415

Answers (3)

Harshith J.V.
Harshith J.V.

Reputation: 887

I will try to do it this way:

1) Save your abstract class in test_case.py

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

2) Save all your child classes in in 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) Save main function in 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) Execute the main.py script:

$ python main.py

Note: One more thing, the folder in which you will save these files should also contain an empty __init__.py file to make that folder as python app(something like packages in Java or namespaces in C++). If you don't then those import statements will not work, probably.

[ Update for running test_cases from different files ]

1) Keep the files in following heirarchy:

<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) Save your abstract class in test_case/test_case.py

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

3) Save sub-classes like this:

File: 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

File: 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

File: 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) Save main function in 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) Execute the main.py script:

$ cd test_case/
$ python main.py

I hope this would work for you.

Upvotes: 0

Andreas Florath
Andreas Florath

Reputation: 4612

This is a meta answer - which means that I think that you should think about your design calling tests.

In python there are well established ways to write tests. [1] And there are also tools which collect all the available tests and executes them (including stats, coverage, xml output, ...). [2]

If I were you I would have a look at them. If you can use them, there is no need to re-invent the wheel.

[1] http://docs.python.org/library/unittest.html
[2] http://readthedocs.org/docs/nose/en/latest/

Upvotes: 2

Ignacio Vazquez-Abrams
Ignacio Vazquez-Abrams

Reputation: 798754

Use a decorator to enumerate the classes, and execute the methods with a list comprehension.

Upvotes: 0

Related Questions