How to verify whether a function has been hit with pytest - python

I have tried this:
def test_send_confirm_hit(monkeypatch):
hit = False
def called():
global hit
hit = True
monkeypatch.setattr("web.email.send_confirm", called)
# ... some event that will cause web.email.send_confirm to be hit
assert hit # verify send_confirm was hit
Which appears to work although I would rather not use a global variable. What is the best way to do this?

If you use a "proper" mock, it comes with an .assert_called() method:
import unittest.mock
def test_send_confirm_hit(monkeypatch):
mock_send_confirm = unittest.mock.Mock()
monkeypatch.setattr("web.email.send_confirm", mock_send_confirm)
# ... some event that will cause web.email.send_confirm to be hit
mock_send_confirm.assert_called()

You could use a Mock instead of the function:
from unittest.mock import MagicMock
def test_send_confirm_hit(monkeypatch):
called = MagicMock()
monkeypatch.setattr("web.email.send_confirm", called)
# ... some event that will cause web.email.send_confirm to be hit
assert called.call_count == 1 # verify send_confirm was hit
If you really need to perform some custom logic, like you would do with a function, you can add a side_effect to the mock:
def test_send_confirm_hit(monkeypatch):
def side_effect():
return 42
called = MagicMock(side_effect=side_effect)

Related

Pytest, how to use a context manager to allow Mock to be used only for certain code?

I'm trying to use Pytest to test Python code. The code I'm testing isn't a class but is a bunch of functions in the same file that call other functions in the same file. For example advanced_function1 calls basic_function, and advanced_function2 can also call basic_function.
When I file.basic_function = Mock() in a test it isn't scoped to just that test.
I can verify this because when I run the test (test_advanced_function1) that mocks basic_function then test_advanced_function2 does not pass. However if I only run test_advanced_function2 (meaning basic_function never gets mocked in another test) then it works.
To my knowledge the way to correct this is to use a context manager in test_advanced_function1 and mock basic_function as that context manager. I don't know how to do this.
To simplify things and more directly declare intent I've got a test that checks if the function is a Mock object or not.
myfile.py
def basic_function():
return True
def advanced_function1():
return basic_function()
def advanced_function2():
return not basic_function()
test_myfile.py
from unittest.mock import Mock
import myfile
def test_basic_function(monkeypatch):
assert myfile.basic_function() == True
def test_advanced_function1():
myfile.basic_function = Mock(return_value='foo')
assert myfile.basic_function() == 'foo'
def test_advanced_function2():
assert not isinstance(myfile.basic_function, Mock)
So, how do I use a context manager in test_advanced_function1 to mock basic_function?
EDIT: To clarify, I can't assign the mock as a fixture because there are multiple test cases that run in the real code I'm working on and I can't mock basic_function for all the asserts in advanced_function1. Yes I know I should break this massive test apart into smaller tests but I'm just learning the codebase and don't want to change too much before getting all their tests working again.
The mock.patch context manager is seldom used directly in pytest. Instead we use fixtures. The plugin pytest-mock provides a fixture for using the mock.patch API in a more "pytest-thonic" way, like this:
import pytest
import myfile
def test_basic_function():
assert myfile.basic_function() == True
def test_advanced_function1(mocker):
mocker.patch("myfile.basic_function", return_value="foo")
assert myfile.advanced_function1() == 'foo'
def test_advanced_function2():
assert myfile.advanced_function2() == False
One possible solution is to use patch in a context manager.
test_myfile.py
from unittest.mock import patch
from unittest.mock import Mock
import myfile
def test_basic_function(monkeypatch):
assert myfile.basic_function() == True
def test_advanced_function1():
with patch('myfile.basic_function') as basic_function:
basic_function.return_value = 'foo'
assert myfile.basic_function() == 'foo'
def test_advanced_function2():
assert not isinstance(myfile.basic_function, Mock)
But please let me know if there's a more elegant way to do this!

Is there a way to mock a complete bit of code in pytest using mock?

For instance, every time a test finds
database.db.session.using_bind("reader")
I want to remove the using_bind("reader")) and just work with
database.db.session
using mocker
Tried to use it like this in conftest.py
#pytest.fixture(scope='function')
def session(mocker):
mocker.patch('store.database.db.session.using_bind', return_value=_db.db.session)
But nothing has worked so far.
Code under test:
from store import database
results = database.db.session.using_bind("reader").query(database.Order.id).join(database.Shop).filter(database.Shop.deleted == False).all(),
and I get
AttributeError: 'scoped_session' object has no attribute 'using_bind' as an error.
Let's start with an MRE where the code under test uses a fake database:
from unittest.mock import Mock, patch
class Session:
def using_bind(self, bind):
raise NotImplementedError(f"Can't bind {bind}")
def query(self):
return "success!"
database = Mock()
database.db.session = Session()
def code_under_test():
return database.db.session.using_bind("reader").query()
def test():
assert code_under_test() == "success!"
Running this test fails with:
E NotImplementedError: Can't bind reader
So we want to mock session.using_bind in code_under_test so that it returns session -- that will make our test pass.
We do that using patch, like so:
#patch("test.database.db.session.using_bind")
def test(mock_bind):
mock_bind.return_value = database.db.session
assert code_under_test() == "success!"
Note that my code is in a file called test.py, so my patch call applies to the test module -- you will need to adjust this to point to the module under test in your own code.
Note also that I need to set up my mock before calling the code under test.

python mocking check if a method of an object was accessed(not called)

class A():
def tmp(self):
print("hi")
def b(a):
a.tmp # note that a.tmp() is not being called. In the project I am working on, a.tmp is being passed as a lambda to a spark executor. And as a.tmp is being invoked in an executor(which is a different process), I can't assert the call of tmp
I want to test whether a.tmp was ever invoked. How do I do that? Note that I still don't want to mock away the tmp() method and would prefer something on the lines of python check if a method is called without mocking it away
Not tested, and there's probably a much better way with Mock but anyway:
def mygetattr(self, name):
if name == "tmp":
self._tmp_was_accessed = True
return super(A, self).__getattribute__(name)
real_getattr = A.__getattribute__
A.__getattribute__ = mygetattr
try:
a = A()
a._tmp_was_accessed = False
b(a)
finally:
A.__getattribute__ real_getattr
print(a._tmp_was_accessed)

Mocking a function

i try to figure how to mock a function in a helper.py that use in several methods for a unit test.
I try with patch, #patch('project.helpers.function_0', new=lambda: True) but didn't work.
How is the correct way to do this?
Thank you.
Update
I have 1 function and 1 decorator that i need to override for all test set.
helpers.py
def myfunction(asd):
# ...
return asd
decorators.py
def mydecorator(func):
#wraps(func)
def _wrapped_func(asd, *args, **kwargs):
# ...
return func(asd, *args, **kwargs)
return _wrapped_func
How i resolved
I want to know how do this with mock, thank you!
test_base.py
import project.decorators
import project.helpers
def myfunction_mock(asd):
# ...
return asd
helpers.myfunction = myfunction_mock
def mydecorator_mock(func):
# ...
decorators.mydecorator = mydecorator_mock
Some key things going on here.
If possible, you should be using unittest.mock (or mock installed via pip).
You are likely patching in the wrong location.
When using mock.patch you probably want to use the new_callable keyword argument, rather than new
Suppose your production code looks something like this....
#production_module.py
from helpers import myfunction
def some_function(a):
result = myfunction(a) + 1
return result
If you wanted to test some_function from your production code, mocking myfunction your test code should patch production_module.myfunction not helpers.myfunction
So your test code may look like this
import mock
from production_module import some_function
def mock_myfunction(*args, **kwargs):
return 1
#mock.patch('production_module.myfunction', new_callable=mock_myfunction)
def test_some_function(mock_func):
result = some_function(1) # call the production function
assert mock_func.called # make sure the mock was actually used
assert result == 2
Another way of using mock.patch is as a context manager. So the patch will only apply in that context.
with mock.patch(...) as mock_func:
some_function(1) # mock_func is called here
some_function(1) # the mock is no longer in place here

Testing a function call inside the function using python unittest framework

I want to test this class using python unittest framework and also mockito.
class ISightRequestEngine(object):
def __init__(self, pInputString=None):
self.__params = (pInputString)
def openHTTPConnection(self):
pass
def __closeHTTPConnection(self):
pass
def testFunc(self):
print 'test function called'
def startEngine(self):
self.__params.parseinputString()
self.openHTTPConnection()
self.testFunc()
def processRequest(self, header = None):
pass
I wanted to test that function startEngine() calls testFunc().
Similar to what we do in our mocked class,
obj = mock(ISightRequestEngine)
obj.startEngine()
try:
verify(obj).startEngine()
except VerificationError:
Unfortunately this only verifies whether the startEngine function is called or not, but it does not give the actual function call and I cannot verify that whether the call to testFunc() has been made or not.
Is there any way to test this scenario?
I am new to testing world and framework.
In your example you are testing your mock.
You create a mock of ISightRequestingEngine
You call startEngine() method of that mock
You verify that the mocked object was called
What you want to do is:
Mock out testFunc()
Call startEngine()
Verify that testFunc() was called
I'm not familiar with mockito, but what from what I can make up from the documentation, I think you have to do something like the following:
from mockito import mock, verify
# Setup ---------------------------------------------
my_mock = mock(ISightRequestingEngine)
system_under_test = ISightRequestingEngine()
system_under_test.testFunc = my_mock.testfunc # Mock out only testFunc()
# Exercise ------------------------------------------
system_under_test.startEngine()
# Verify --------------------------------------------
verify(my_mock).testFunc()
Having similar such issue, where I am bit lost in writing the test case
class UserCompanyRateLimitValidation:
def __init__(self, user_public_key):
self.adapter = UserAdapter(user_public_key)
container = self.adapter.get_user_company_rate_limit()
super(UserCompanyRateLimitValidation, self).__init__(container,\
UserCompanyRateLimitValidation.TYPE)
I have to test this function. I have written test case something like this. I have tried to mock the UserAdapter class but I am not able to do so completely.
def test_case_1():
self.user_public_key = 'TEST_USER_PUBLIC_KEY_XXXXXX1234567890XXXXX'
UserAdapter_mock = mock(UserAdapter)
when(UserAdapter_mock).get_user_company_rate_limit().\
thenReturn(self.get_container_object())
self.test_obj = UserCompanyRateLimitValidation(self.user_public_key)
Here if you see I have mocked get_user_company_rate_limit() call from the testable function, container = self.adapter.get_user_company_rate_limit()
but I am still not able to figure out the way in which I can mock this call,
self.adapter = UserAdapter(user_public_key)

Categories

Resources