Reputation: 3025
I am writing tests in my app that will test whether a method was called. This is running in Python 3.4.3 and pytest-2.9.2. I am new to PyTest but very familiar with RSpec and Jasmine. I'm not sure how to setup the test so that it will test that imaplib.IMAP4_SSL is called.
My app structure:
/myApp
__init__.py
/shared
__init__.py
email_handler.py
/tests
__init__.py
test_email_handler.py
email_handler.py
import imaplib
def email_conn(host):
mail = imaplib.IMAP4_SSL(host)
return mail;
What I have so far for my test: test_email_handler.py
import sys
sys.path.append('.')
from shared import email_handler
def test_email_handler():
email_handler.email_conn.imaplib.IMAP4_SSL.assert_called_once
This obviously fails. How can I setup this test so that it tests if imaplib.IMAP4_SSL is called? Or is there a better way to setup the test suite in my app so this will support testing more effectively?
Upvotes: 4
Views: 3895
Reputation: 1570
Here's an example using unittest.mock
from the Python 3.5.2 standard library:
test_email_handler.py
import sys
from unittest import mock
sys.path.append('.')
from shared import email_handler
@mock.patch.object(email_handler.imaplib, 'IMAP4_SSL')
def test_email_handler(mock_IMAP4_SSL):
host = 'somefakehost'
email_handler.email_conn(host)
mock_IMAP4_SSL.assert_called_once_with(host)
Note the @mock.patch.object
decorator that replaces IMAP4_SSL with a mock object, which is added as an argument. Mock is a powerful tool for testing that can be quite confusing for new users. I recommend the following for further reading:
https://www.toptal.com/python/an-introduction-to-mocking-in-python
http://engineroom.trackmaven.com/blog/mocking-mistakes/
http://alexmarandon.com/articles/python_mock_gotchas/
Upvotes: 3
Reputation: 2089
This sounds like a question of code coverage: was this line executed?
For python coverage tool is: https://coverage.readthedocs.io
Pytest built plugin based on that tool, which is very convenient: https://pypi.python.org/pypi/pytest-cov
Upvotes: 0
Reputation: 1499
what you can do is this :
email_handler.py
import imaplib
def email_conn(host):
print("We are in email_conn()")
mail = imaplib.IMAP4_SSL(host)
print(mail)
return mail;
test_email_handler.py
import sys
sys.path.append('.')
from shared import email_handler
def test_email_handler():
print("We are in test_email_handler()")
email_handler.email_conn.imaplib.IMAP4_SSL.assert_called_once
print(email_handler.email_conn.imaplib.IMAP4_SSL.assert_called_once) # this will give you the result of the function (in theory)
Basically, what you do is printing what the functions returns. If there is no error, the function should have been executed.
What you could also do, is modifying the source code of imaplib in order to put a print inside the function you're calling.
Good luck !
Upvotes: 0