Python - Testing an abstract base class

前端 未结 6 1346
醉话见心
醉话见心 2020-12-04 16:27

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 subclas

6条回答
  •  悲&欢浪女
    2020-12-04 17:24

    Here is what I have found: If you set __abstractmethods__ attribute to be an empty set you'll be able to instantiate abstract class. This behaviour is specified in PEP 3119:

    If the resulting __abstractmethods__ set is non-empty, the class is considered abstract, and attempts to instantiate it will raise TypeError.

    So you just need to clear this attribute for the duration of tests.

    >>> import abc
    >>> class A(metaclass = abc.ABCMeta):
    ...     @abc.abstractmethod
    ...     def foo(self): pass
    

    You cant instantiate A:

    >>> A()
    Traceback (most recent call last):
    TypeError: Can't instantiate abstract class A with abstract methods foo
    

    If you override __abstractmethods__ you can:

    >>> A.__abstractmethods__=set()
    >>> A() #doctest: +ELLIPSIS
    <....A object at 0x...>
    

    It works both ways:

    >>> class B(object): pass
    >>> B() #doctest: +ELLIPSIS
    <....B object at 0x...>
    
    >>> B.__abstractmethods__={"foo"}
    >>> B()
    Traceback (most recent call last):
    TypeError: Can't instantiate abstract class B with abstract methods foo
    

    You can also use unittest.mock (from 3.3) to override temporarily ABC behaviour.

    >>> class A(metaclass = abc.ABCMeta):
    ...     @abc.abstractmethod
    ...     def foo(self): pass
    >>> from unittest.mock import patch
    >>> p = patch.multiple(A, __abstractmethods__=set())
    >>> p.start()
    {}
    >>> A() #doctest: +ELLIPSIS
    <....A object at 0x...>
    >>> p.stop()
    >>> A()
    Traceback (most recent call last):
    TypeError: Can't instantiate abstract class A with abstract methods foo
    

提交回复
热议问题