How to MagicMock the function within function python - python-3.x

I have a module A, which contains below two functions:
def my_func():
my_dict = {"key1":100, "key2": 100}
send_result(dicts=my_dict)
def send_result(dicts):
print(dicts)
I have written unit test case as below:
from unittest.mock import MagicMock
import A
def test_send_results(self, dicts):
self.assertGreater(len(dicts), 0)
def test_my_func(self):
A.send_result = MagicMock(wraps=self.test_send_results)
A.my_func()
And when I am running unit test case, I am getting below error though dicts contains the value:
TypeError: test_send_results() missing 1 required positional argument: 'dicts'

As suggested by Anthony, use patch.object. An example given below:
import unittest
from unittest import mock
import A
class MyTestClass(unittest.TestCase):
def test_send_results(self, dicts):
self.assertGreater(len(dicts), 0)
#mock.patch.object(self, 'test_send_results')
def test_my_func(self, mock_func):
mock_func.return_value = 'something'
A.my_func()

Related

Pytest object created by object assert_called_once_with

I known how I can test if an injected object was called with a specific argument. But in my case the injected object will create an object that object will create another object and I want to test if that last object was called with the right argument.
in the example below the question would be if c.dirve was called with 100 as argument:
class car:
def drive(self, distance):
print("so fast")
class car_shop:
def buy_car(self):
return car()
class shop_shop:
def buy_shop(self):
return car_shop()
class processor:
def __init__(self, sshop):
self.sshop = sshop
def run(self):
cshop = self.sshop.buy_shop()
c = cshop.buy_car()
c.drive(100)
def main():
sshop = shop_shop()
proc = processor(sshop)
proc.run()
if __name__ == "__main__":
main()
is there a way to test that?
Since this was requested here my approach for testing these objects:
import pytest
from unittest.mock import Mock
from object_returns_object_test_for_arguments import processor, shop_shop
#pytest.fixture
def mock_shop_shop():
return Mock(spec=shop_shop)
def test_processor_car_called_with_100(mock_shop_shop):
proc = processor(mock_shop_shop)
proc.run()
assert mock_shop_shop.car_shop.car.drive.assert_called_once_with(100)
assert mock_shop_shop.car_shop.car.drive.call_count == 1
If using just the code shown in the question, you only have to mock car.drive. This could be done for example this way:
from unittest import mock
from object_returns_object_test_for_arguments import processor, shop_shop
#mock.patch('object_returns_object_test_for_arguments.car.drive')
def test_processor_car_called_with_100(drive_mock):
proc = processor(shop_shop())
proc.run()
drive_mock.assert_called_once_with(100)
As I don't know your real code, you may have to mock more stuff.
As an aside: class names in Python are written upper-case, camelcase-style by default.

Mocking a class in a Flask API

I have three files
helper.py
class helper:
def __init__(self, out_file):
self.out_file = out_file
def foo(first, second):
# Write data to file
flask_API.py
from helper import helper
#app.route('/', methods=['POST'])
def parse_request():
content = request.get_json()
out_file = #based on timestamp
helper(out_file).foo(content['first'], content['second'])
test_flask.py
import unittest
from unittest.mock import patch
import flask_API
class testFlaskAPI(unittest.TestCase):
def setUp(self):
self.app = flask_API.app.test_client()
self.app.test = True
#patch('flask_API.app.helper', return_value=None)
def test_service(self, mock_helper):
response = self.app.post(base_url, data=json.dumps({"some":"value"}, content_type='application/json')
self.assertEqual(response.status_code, status.HTTP_200_OK)
I am having trouble mocking the helper class. This gives me an error saying
AttributeError: <Flask 'flask_API'> does not have the attribute 'helper'
I read that a class/method needs to be mocked where it is being called instead of where it's defined. Is there something wrong with the way I am patching the class?
In the end the solution turned out to be fairly simple. First there was no need to add app in the #patch decorator. The test just needed #patch('flask_API.helper'). Second, I first needed to return the mock of the class and then mock the function call as well. So the final answer turned out to be
#patch('flask_API.helper')
def test_service(self, mock_helper):
mocking_helper = mock_helper.return_value # mocking the class
mocking_helper.foo.return_value = None
response = self.app.post(base_url, data=json.dumps({"some":"value"}, content_type='application/json')
self.assertEqual(response.status_code, status.HTTP_200_OK)

python mocking function calls that are called during module import

I need to perform mocking for python code that is running during module import
For example I have code like this
import configparser
config = configparser.ConfigParser()
config.read('test.ini')
a = float(config['config']['a'])
b = float(config['config']['b'])
c = float(config['config']['c'])
print(a)
print(b)
print(c)
I need mock "config" for testing
import pytest
import mock
import app
#mock.patch('app.configparser.ConfigParser')
def test_config_mock(config_mock):
config_mock.return_value = {'config': { 'a' : 1 } }
However, this testing function being called after actual import so my mocking is not making any sense
What's the right way of doing this kind of thing?
What you can do in this case is to instead patch the config instance using mock.patch.dict:
# test_coolio.py
import mock
from app.fun import coolio
#mock.patch.dict('app.configparser.config', values={'config': {'a': 15}})
def test_config_mock():
assert coolio() == '15'
# app/fun.py
from app.configparser import config
def coolio():
return config['config']['a']

Using pytest, how do I mock pathlib's Path.isdir() function together with os.listdir

I am trying to write a pytest test for this function.
It looks for folders named like a day.
from settings import SCHEDULE
from pathlib import Path
import os
import datetime
def get_schedule_dates():
schedule_dates = []
for dir in os.listdir(SCHEDULE): # schedule is a path to a lot of directories
if Path(SCHEDULE, dir).is_dir():
try:
_ = datetime.datetime.strptime(dir, '%Y-%m-%d')
schedule_dates.append(dir)
except ValueError:
pass
return schedule_dates
Mocking os.listdir works fine. (when I turn off the isdir check)
from mymod import mycode as asc
import mock
def test_get_schedule_dates():
with mock.patch('os.listdir', return_value=['2019-09-15', 'temp']):
result = asc.get_schedule_dates()
assert '2019-09-15' in result
assert 'temp' not in result
Mocking pathlib's Path at the same time doesn't work:
def test_get_schedule_dates():
with (mock.patch('os.listdir', return_value=['2019-09-15', 'temp']),
mock.patch('pathlib.Path.isdir', return_value=True)):
result = asc.get_schedule_dates()
assert '2019-09-15' in result
assert 'temp' not in result
I get the error:
E AttributeError: __enter__
How can I mock both listdir and Path in the same call?
It looks like I can only use one mock per with statement,
testing this way works.
def test_get_schedule_dates():
with mock.patch('os.listdir', return_value=['2019-09-15', 'temp']):
with mock.patch('pathlib.Path.is_dir', return_value=True):
result = asc.get_schedule_dates()
assert '2019-09-15' in result
assert 'temp' not in result

Python 3 threadings.Thread callback error when targeting abstract method

base_class.py
import threading
import websocket
from abc import ABCMeta, abstractmethod
class A:
__metaclass__ = ABCMeta
def __init__(self):
self.some_var = 0
#abstractmethod
def failed_method(self):
pass
def on_websocket_message(self, ws, msg):
var = self.failed_method()
print(var)
...
def open_websocket(self):
ws = websocket.WebSocketApp('http://some_url.com',
on_message=self.on_websocket_message, ...)
ws.run_forever()
def callback_method(self):
websocket_thread = threading.Thread(target=self.open_websocket, name='some_websocket_name')
another_var = self.failed_method()
print('Another variable\'s value is [{}]'.format(another_var))
child_class.py
from base_class import A
class B(A):
def failed_method(self):
return 3
other_class.py
import threading
from child_class import B
def main():
child_class_instance = B()
some_thread = threadings.Thread(target=child_class_instance.callback_method, name='some_name')
some_thread.start()
The result of main() is printed None, not 3, i.e., abstract class' method is called instead of child's one. (Assume all the modules are in the one place.)
Can anyone explain this behaviour? Or what is the thing I do not understand in inheritance in Python combined with threadings.Thread?
P.S. With the similar code I've met error from callback <bound method BaseClass... of < ...ChildClass...> > from websocket.WebSocketApp._callback().
P.P.S. Important to note that I use websocket-client, not websockets.

Resources