Why is mocking out zeep.Client not working?
Question:
I’m writing unit tests for a piece of code that uses zeep to access a SOAP API so I want to mock out zeep. In my actual code, it looks something like this:
from zeep import Client
def do_something():
client = Client("...")
In my test, I’m doing this:
from unittest import mock
@mock.patch('zeep.Client')
def test_do_somethi(self, MockedClient):
do_something()
The Client
that the actual function is obtaining, is the actual zeep client and not my mock. I also tried:
@mock.patch('zeep.client.Client')
and the result was the same.
I also tried:
def test_do_something(self):
with mock.patch('zeep.client.Client') as MockedClient:
do_something()
with no difference.
Any ideas why this isn’t working?
Answers:
When mock doesn’t work, the first thing to look for is if you are patching the right name. Three common import scenarios:
(a) If you want to mock out zeep
but you import like
from zeep import Client
and your tests are in the same file, you patch Client
not zeep.Client
.
(b) If instead you import it like
import zeep
and then use zeep.Client
in SUT code, then you patch zeep.Client
.
(c) If you are testing code that lies in some other module (like mymodule
) and you import zeep
there with
from zeep import Client # (1)
then in your test module you
import mymodule
then you patch mymodule.Client
, … or mymodule.zeep.Client
if you used the alternative import zeep
form in (1).
You must patch the method/class from file you are using it. If you want to patch Client
and it is imported in some_file.py you must import it from it, and not from lib (zeep.Client
)
Here is an example using the official doc from Zeep.
some_lib.py
from zeep import Client
def do_something():
wsdl = 'http://www.soapclient.com/xml/soapresponder.wsdl'
client = zeep.Client(wsdl=wsdl)
return client.service.Method1('Zeep', 'is cool')
test_connection.py
from some_lib import do_something
from unittest.mock import patch
@patch('some_lib.Client')
def test_do_something(mock_zeep):
res = do_something()
assert mock_zeep.call_count == 1
if __name__ == '__main__':
test_soap_conn()
I’m writing unit tests for a piece of code that uses zeep to access a SOAP API so I want to mock out zeep. In my actual code, it looks something like this:
from zeep import Client
def do_something():
client = Client("...")
In my test, I’m doing this:
from unittest import mock
@mock.patch('zeep.Client')
def test_do_somethi(self, MockedClient):
do_something()
The Client
that the actual function is obtaining, is the actual zeep client and not my mock. I also tried:
@mock.patch('zeep.client.Client')
and the result was the same.
I also tried:
def test_do_something(self):
with mock.patch('zeep.client.Client') as MockedClient:
do_something()
with no difference.
Any ideas why this isn’t working?
When mock doesn’t work, the first thing to look for is if you are patching the right name. Three common import scenarios:
(a) If you want to mock out zeep
but you import like
from zeep import Client
and your tests are in the same file, you patch Client
not zeep.Client
.
(b) If instead you import it like
import zeep
and then use zeep.Client
in SUT code, then you patch zeep.Client
.
(c) If you are testing code that lies in some other module (like mymodule
) and you import zeep
there with
from zeep import Client # (1)
then in your test module you
import mymodule
then you patch mymodule.Client
, … or mymodule.zeep.Client
if you used the alternative import zeep
form in (1).
You must patch the method/class from file you are using it. If you want to patch Client
and it is imported in some_file.py you must import it from it, and not from lib (zeep.Client
)
Here is an example using the official doc from Zeep.
some_lib.py
from zeep import Client
def do_something():
wsdl = 'http://www.soapclient.com/xml/soapresponder.wsdl'
client = zeep.Client(wsdl=wsdl)
return client.service.Method1('Zeep', 'is cool')
test_connection.py
from some_lib import do_something
from unittest.mock import patch
@patch('some_lib.Client')
def test_do_something(mock_zeep):
res = do_something()
assert mock_zeep.call_count == 1
if __name__ == '__main__':
test_soap_conn()