pythonooptestingabc

Python - Testing an abstract base class


I am looking for ways / best practices on testing methods defined in an abstract base class. One thing I can think of directly is performing the test on all concrete subclasses of the base class, but that seems excessive at some times.

Consider this example:

import abc

class Abstract(object):

    __metaclass__ = abc.ABCMeta

    @abc.abstractproperty
    def id(self):
        return   

    @abc.abstractmethod
    def foo(self):
        print "foo"

    def bar(self):
        print "bar"

Is it possible to test bar without doing any subclassing?


Solution

  • As properly put by lunaryon, it is not possible. The very purpose of ABCs containing abstract methods is that they are not instantiatable as declared.

    However, it is possible to create a utility function that introspects an ABC, and creates a dummy, non abstract class on the fly. This function could be called directly inside your test method/function and spare you of having to wite boiler plate code on the test file just for testing a few methods.

    def concreter(abclass):
        """
        >>> import abc
        >>> class Abstract(metaclass=abc.ABCMeta):
        ...     @abc.abstractmethod
        ...     def bar(self):
        ...        return None
    
        >>> c = concreter(Abstract)
        >>> c.__name__
        'dummy_concrete_Abstract'
        >>> c().bar() # doctest: +ELLIPSIS
        (<abc_utils.Abstract object at 0x...>, (), {})
        """
        if not "__abstractmethods__" in abclass.__dict__:
            return abclass
        new_dict = abclass.__dict__.copy()
        for abstractmethod in abclass.__abstractmethods__:
            #replace each abc method or property with an identity function:
            new_dict[abstractmethod] = lambda x, *args, **kw: (x, args, kw)
        #creates a new class, with the overriden ABCs:
        return type("dummy_concrete_%s" % abclass.__name__, (abclass,), new_dict)