I have a class that mocks database functionality which does not subclass Mock or MagicMock because it defines its own __init__ method:
class DatabaseMock():
def __init__(self, host=None):
self.host = host
self.x = {}
# other methods that mutate x
There is a function I want to test that makes an API call to the real database, so I patched it out:
class TestFunctions():
def test_function(self):
with patch("path.to.database.call", DatabaseMock) as mock:
result = function_i_am_testing()
assert mock.x == result
There is a field of the DatabaseMock called x, but in the patch context, mock.x returns an AttributeError. This leads to me believe mock is not really an instance of DatabaseMock. Also, I had tried making x a class level object which does make x visible, but its state would persist through separate test calls which I do not want. What is mock and how can I reference the mocked object in the context?
CodePudding user response:
You are indeed calling patch
correctly, so the problem may be with your DatabaseMock
(which does not have an x
attribute in the code you've provided), or perhaps with your actual test function.
Here's a simple example demonstrating that mock
(the object returned by the context manager) is created by calling the new
argument, and takes the place of the patch target
within the context:
>>> class Foo:
... x = 0
...
>>> class FooMock:
... x = 42
...
>>> from unittest.mock import patch
>>> with patch("__main__.Foo", FooMock) as mock:
... print(mock.x)
... print(Foo.x)
...
42
42
>>> print(Foo.x)
0
If you still have doubts about what mock
is, try adding a print(mock)
to your test function.
CodePudding user response:
I have figured out the issue. When patch is given a class, it will return a class, not an object of that class. So mock in my example is not a DataBaseMock object, but a reference to the class. This is why class level variables are visible, but not object fields. In order get my desired functionality, I did this:
class TestFunctions():
def test_function(self):
with patch("path.to.database.call") as mock:
mock.return_value = DataBaseMock()
result = function_i_am_testing()
assert mock.return_value.x == result
Now, mock is a MagicMock object, whose return value is the object I need.