Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to use abc abstract base class as mock spec?

I have an abstract base class:

import abc
import six

@six.add_metaclass(abc.ABCMeta)
class A(object):

    @abc.abstractmethod
    def f(self, arg1):
        pass

I'd like to use this class as a spec for a mock.

import mock
mock_a = mock.Mock(spec=A)

This works partially. For example, mock_a.x results in AttribureError("Mock object has no attribute 'x'). However mock_a.f is not speced based on the abstract method from A.f. It returns a mock regardless of the number of arguments passed to f.

mock_a = mock.Mock(spec=A)

# Succeeds
print mock_a.f(1)

# Should fail, but returns a mock
print mock_a.f(1,2)

# Correctly fails
print mock_a.x

Mock can create a mock speced from A.f with create_autospec ...

f_spec = mock.create_autospec(A.f)

# Succeeds
f_spec(mock_a, 1)

# Correctly fails
f_spec(mock_a, 1, 2)

... but doesn't do so for the attributes of A

How can I create a mock that accurately implements the abstract base class?

like image 595
Cirdec Avatar asked Feb 28 '17 18:02

Cirdec


People also ask

How do you use an abstract base class?

Abstract classes make sure that derived classes implement methods and properties defined in the abstract base class. Abstract base class can't be instantiated. We use @abstractmethod to define a method in the abstract base class and combination of @property and @abstractmethod in order to define an abstract property.

What is an abstract base class ABC )?

A class is called an Abstract class if it contains one or more abstract methods. An abstract method is a method that is declared, but contains no implementation. Abstract classes may not be instantiated, and its abstract methods must be implemented by its subclasses.

How do you test an ABC class in Python?

There are two options to test an abstract base class (ABC) in Python: you can either override or patch the __abstractmethods__ property to be able to instantiate the abstract class and test it directly or you can create a child class that implements all the abstract methods of the base class.

What does ABC Abstractmethod do?

@abc. abstractmethod prevents any attempt to instantiate a subclass that doesn't override a particular method in the superclass.


1 Answers

Apply mock.create_autospec() to the class:

>>> mock_a = mock.create_autospec(spec=A)
>>>
>>> # Should succeed
>>> print mock_a.f(1)
<MagicMock name='mock.f()' id='140401932347984'>
>>>
>>> # Should fail
>>> print mock_a.f(1,2)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/lib/python2.7/dist-packages/mock/mock.py", line 1061, in __call__
    _mock_self._mock_check_sig(*args, **kwargs)
  File "/usr/lib/python2.7/dist-packages/mock/mock.py", line 227, in checksig
    sig.bind(*args, **kwargs)
  File "/usr/lib/python2.7/dist-packages/mock/mock.py", line 95, in fixedbind
    return self._bind(args, kwargs)
  File "/usr/lib/python2.7/dist-packages/funcsigs/__init__.py", line 712, in _bind
    raise TypeError('too many positional arguments')
TypeError: too many positional arguments
>>>
>>> # Should fail
>>> print mock_a.x
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/lib/python2.7/dist-packages/mock/mock.py", line 716, in __getattr__
    raise AttributeError("Mock object has no attribute %r" % name)
AttributeError: Mock object has no attribute 'x'
>>> 
like image 150
Leon Avatar answered Sep 22 '22 01:09

Leon