Mocking a while statment Python - python-3.x

Im pretty new at mocking in Python. I searched pretty deeply for any post that answered this question, but i failed to do so. I want to mock a function that is called within a while statement. Is there anyway to do this?
def some_function(self, some_param):
some_counter = 0
while self.func_i_want_to_mock(mock_param, mock_param2) is False:
some_counter += 1
return some_counter

I want to mock a function that is called within a while statement
Define a side effect function if you want to play with the parameters
def func_tbm_side_effect(first, second):
return 'whatever'
Now with the testing
import unittest
import mock
import ClassWithSomeFunc
class TestClassWithSomeFunc(unittest.TestCase):
def test_some_function(self):
with mock.patch.object(ClassWithSomeFunc, 'some_function') as mocked_sf:
mocked_sf.side_effect = func_tbm_side_effect
item = ClassWithSomeFunc()
value = item.some_function('parameter')
self.assertEqual(value, 'endless loop')

def some_function(self, some_param):
some_counter = 0
while self.func_i_want_to_mock(mock_param, mock_param) is False:
some_counter += 1
return some_counter
def func_i_want_to_mock(mock_param, mock_param):
if mock_param1 == x and mock_param2 == y:
return True
elif """ ... all cases"""

Related

Nested function in Python class

i have a little "basic understanding" Python problem.
So let me explain my problem.
At first a very simple code snippet.
class Revert:
__sentence = ""
def __init__(self, sentence: str):
self.__sentence = sentence
def get_sentence(self):
return self.__sentence
def revert_sentence(self):
return self.__sentence[::-1]
if __name__ == '__main__':
print(Revert("Stackoverflow").get_sentence())
print(Revert("Stackoverflow").revert_sentence())
So this show normal function calling of python functions.
But how can i transform this code so i can call the revert function like this:
print(Revert("Stackoverflow").get_sentence().revert_sentence())
Maybe I'm miss the forest through the trees. But I didn't get it how to do this.
I already tried to solve the problem with innermethods but this didn't work for me
...
def get_sentence(self):
def revert_sentence():
self.revert_sentence()
return self.__sentence
...
Many thanks in advance
Implement __str__ to return the actual string. Then in the existing methods, return the object. This way you can chain. But when print is applied to it, that __str__ method will kick in:
class Revert:
__sentence = ""
def __init__(self, sentence: str):
self.__sentence = sentence
def get_sentence(self):
return self
def revert_sentence(self):
return Revert(self.__sentence[::-1])
# Some more such methods ...
def upper(self):
return Revert(self.__sentence.upper())
def first(self, count):
return Revert(self.__sentence[:count])
def dotted(self):
return Revert(".".join(self.__sentence))
# For getting a string
def __str__(self):
return self.__sentence
print(Revert("Stackoverflow").get_sentence().revert_sentence())
print(Revert("Stackoverflow")
.revert_sentence()
.first(8)
.upper()
.revert_sentence()
.first(4)
.dotted()) # "O.V.E.R"
Note that now the .get_sentence() method is not really doing much, and you can always strip it from a chain.
Here You go:
class Revert:
__sentence = ""
def __init__(self, sentence: str):
self.__sentence = sentence
def get_sentence(self):
return self.__sentence
def revert_sentence(self):
# It's important to know that you are making changes in the same instance of the object
self.__sentence = self.__sentence[::-1]
return self
def pseudo_revert(self):
# Return a new object with reverted string, but this instance still has original string intact.
return Revert(self.__sentence[::-1])
if __name__ == '__main__':
r1 = Revert("Stackoverflow")
r2 = Revert("Stackoverflow")
print(r1.get_sentence()) # Stackoverflow
print(r1.revert_sentence().get_sentence()) # wolfrevokcatS
print(r1.get_sentence()) # wolfrevokcatS
print(r2.get_sentence()) # Stackoverflow
print(r2.pseudo_revert().get_sentence()) # wolfrevokcatS
print(r2.get_sentence()) # Stackoverflow
Hope this helps you understand the object, instance of an object, and method of object distinctly.

Python: mock file input for testing function

I know there are similar posts, but I did not find anything like this one.
I have a function in python that receives as input the filename to be read and process and return something, and I want to test if the output for my function. Example:
#main function
def myfunction(filename):
f=open(filename)
for line in f:
# process data
pass
f.close()
return # something
#test function for the main function
def test_myfunction():
mockfile = #mymockfile
assert myfunction(mockfile) == #something
How could I create a mock file to test this function without having to write a read file?
This was the closest I found to emulate what i need (http://www.voidspace.org.uk/python/mock/helpers.html#mock-open)
Having struggled with the same question, please find my answers below.
update December 2022
I found a simpler solution than my original solution from 2018. Using Python 3.9.2 and running the script from the command line with pytest:
import unittest.mock
#main function
def myfunction(filename):
f=open(filename)
maximum = 0
for line in f:
if maximum < len(line):
maximum = len(line)
pass
f.close()
return maximum
def test_myfunction():
mock_file = unittest.mock.mock_open(read_data=('12characters\n13_characters'))
with unittest.mock.patch('builtins.open', mock_file):
actual_result = myfunction('foo')
assert not actual_result == 12
assert actual_result == 13
original answer 2018
I used Python 3.6 and Py.test through the pydev plugin in Eclipse.
import unittest.mock as mock
from unittest.mock import mock_open
#main function
def myfunction(filename):
f=open(filename)
maximum = 0
for line in f:
if maximum < len(line):
maximum = len(line)
pass
f.close()
return maximum
#test function for the main function
#mock.patch('builtins.open', new_callable=mock_open, create=True)
def test_myfunction(mock_open):
mock_open.return_value.__enter__ = mock_open
mock_open.return_value.__iter__ = mock.Mock(
return_value = iter(['12characters', '13_characters']))
answer = myfunction('foo')
assert not answer == 12
assert answer == 13

Python 3.5 class variables

I'm new to python, and I'm using python 3.5 on Ubuntu. I did some research about this question and i found a lot of answers. What I'm doing looks like what everyone is saying I'm supposed to do, but I'm still receiving errors.
import csv
import sys
Class State():
started = False
def waiting(self):
self.started
if self.started == False:
self.started = True
return
def buy_in(self, col):
if self.started == False:
return
else:
print(col)
def read_file(file):
csv_list = csv.reader(file)
header = True
for row in csv_list:
if header:
header = False
continue
col = float(row[5])
if col < 0 :
State.waiting()
if col >= 0:
State.buy_in(col)
file.close()
def main(filename):
file = open(filename)
read_file(file)
def __name__ == '__main__':
main(sys.argv[1])
I'm just trying to create a pseudo FSM in python, by using a class and methods. I just need to create a global bool. I don't really understand what I'm doing wrong. IF someone doesn't mind giving me some clarity, I would appreciate it. Thanks
To clarify, I'm getting the NameError on the if statement in the buy_in method.
Try:
class State():
started = False
def waiting(self):
if self.started == False:
self.started = True
return
def buy_in(self, col):
if self.started == False:
return
else:
print(col)
Since started is a class variable you need to use self. when calling it. It is not a global variable so you do not need the global call. Each of the methods inside of the class also needs self as an argument.

Python asyncio: how to mock __aiter__() method?

I have a code which is listening to messages on WebSocket using aiohttp.
It looks like:
async for msg in ws:
await self._ws_msg_handler.handle_message(ws, msg, _services)
Where ws is an instance of aiohttp.web.WebSocketResponse() (original code)
In my test I mock WebSocketResponse() and its __aiter__ method:
def coro_mock(**kwargs):
return asyncio.coroutine(mock.Mock(**kwargs))
#pytest.mark.asyncio
#mock.patch('aiojsonrpc.request_handler.WebSocketMessageHandler')
async def test_rpc_websocket_handler(
MockWebSocketMessageHandler,
rpc_websocket_handler
):
ws_response = 'aiojsonrpc.request_handler.WebSocketResponse'
with mock.patch(ws_response) as MockWebSocketResponse:
MockRequest = mock.MagicMock()
req = MockRequest()
ws_instance = MockWebSocketResponse.return_value
ws_instance.prepare = coro_mock()
ws_instance.__aiter__ = coro_mock(return_value=iter(range(5)))
ws_instance.__anext__ = coro_mock()
handle_msg_result = 'Message processed'
MockWebSocketMessageHandler.handle_message.side_effect = Exception(
handle_msg_result)
msg_handler = MockWebSocketMessageHandler()
with pytest.raises(Exception) as e:
await request_handler.RpcWebsocketHandler(msg_handler)(req)
assert str(e.value) == handle_msg_result
Though when I run the test it fails with the error message saying:
'async for' requires an object with __aiter__ method, got MagicMock
=================================================================================== FAILURES ===================================================================================
__________________________________________________________________________ test_rpc_websocket_handler __________________________________________________________________________
MockWebSocketMessageHandler = <MagicMock name='WebSocketMessageHandler' id='140687969989632'>
rpc_websocket_handler = <aiojsonrpc.request_handler.RpcWebsocketHandler object at 0x7ff47879b0f0>
#pytest.mark.asyncio
#mock.patch('aiojsonrpc.request_handler.WebSocketMessageHandler')
async def test_rpc_websocket_handler(
MockWebSocketMessageHandler,
rpc_websocket_handler
):
ws_response = 'aiojsonrpc.request_handler.WebSocketResponse'
with mock.patch(ws_response) as MockWebSocketResponse:
# MockRequest = mock.create_autospec(aiohttp.web_reqrep.Request)
# req = MockRequest(*[None] * 6)
MockRequest = mock.MagicMock()
req = MockRequest()
ws_instance = MockWebSocketResponse.return_value
ret = mock.Mock()
ws_instance.prepare = coro_mock()
ws_instance.__aiter__ = coro_mock(return_value=iter(range(5)))
ws_instance.__anext__ = coro_mock()
handle_msg_result = 'Message processed'
MockWebSocketMessageHandler.handle_message.side_effect = Exception(
handle_msg_result)
msg_handler = MockWebSocketMessageHandler()
with pytest.raises(Exception) as e:
await request_handler.RpcWebsocketHandler(msg_handler)(req)
> assert str(e.value) == handle_msg_result
E assert "'async for' ...got MagicMock" == 'Message processed'
E - 'async for' requires an object with __aiter__ method, got MagicMock
E + Message processed
tests/test_request_handler.py:252: AssertionError
So it behaves like __aiter__() was never mocked.
How I'm supposed to accomplish correct mocking in this case?
Update:
For now I've found a workaround to make the code testable though I would really appreciate if someone tell me how to deal with the issue described in the original question.
You can make the mocked class return an object implementing the expected interface:
class AsyncIterator:
def __init__(self, seq):
self.iter = iter(seq)
def __aiter__(self):
return self
async def __anext__(self):
try:
return next(self.iter)
except StopIteration:
raise StopAsyncIteration
MockWebSocketResponse.return_value = AsyncIterator(range(5))
I don't think there is a way (yet) to correctly mock an object implementing __aiter__, it may be a python bug, as async for rejects a MagicMock, even if hasattr(the_magic_mock, '__aiter__') is True.
EDIT (13/12/2017): the library asynctest supports asynchronous iterators and context managers since 0.11, asynctest.MagicMock provides this feature for free.
For posterity, I had the same problem of needing to test an async for loop, but the accepted solution doesn't seem to work for Python 3.7. The example below works for 3.6.x and 3.7.0, but not for 3.5.x:
import asyncio
class AsyncIter:
def __init__(self, items):
self.items = items
async def __aiter__(self):
for item in self.items:
yield item
async def print_iter(items):
async for item in items:
print(item)
if __name__ == '__main__':
loop = asyncio.get_event_loop()
things = AsyncIter([1, 2, 3])
loop.run_until_complete(print_iter(things))
loop.close()
With the above, mocking it looks something like:
with mock.patch('some.async.iter', return_value=AsyncIter([1, 2, 3])):
# do test requiring mocked iter
Works for py38
from unittest.mock import MagicMock
async def test_iterable(self):
loop_iterations = 0
mock = MagicMock()
mock.__aiter__.return_value = range(5)
async for _ in mock:
loop_iterations += 1
self.assertEqual(5, loop_iterations)
I have a python version that supports AsyncMock and I also leverage pytest_mock. I came up with this solution to this problem combining the use of AsyncMock side_effect:
from typing import List
import pytest
import asyncio
from pytest_mock.plugin import MockerFixture
pytestmark = pytest.mark.asyncio
async def async_generator(numbers: List[int]):
for number in numbers:
yield number
await asyncio.sleep(0.1)
async def function_to_test(numbers: List[int]):
async for thing in async_generator(numbers):
yield thing * 3
await asyncio.sleep(0.1)
async def test_async_generator(mocker: MockerFixture):
mock_numbers = [1, 2, 3, 4, 5]
async def async_generator_side_effect(numbers: List[int]):
for number in numbers:
yield number
mock_async_generator = mocker.patch("tests.test_async_generator.async_generator")
mock_async_generator.side_effect = async_generator_side_effect
actual = []
async for result in function_to_test(mock_numbers):
actual.append(result)
assert actual == [3, 6, 9, 12, 15]

How do i make a unittest ? what does it look like?

def abn_abc(voteslist):
sums = {}
for vote in votes:
if vote in sums:
sums[vote] += 1
else:
sums[vote] = 1
return tally_ballots(sums)
How do I write a unit test for this function?
Something like this:
import unittest
from wherever import abn_abc
class AbnAbcTest(unittest.TestCase):
def test_abn_abc(self):
list_for_testing with = [<insert list here>]
self.assertEqual(abn_abc(list_for_testing_with), <expected result>)
if __name__ == '__main__':
unittest.main()
Here's the documentation.

Resources