Python: mock file input for testing function - python-3.x

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

Related

Function argument with mutables, avoid `if arg is None` construct

Is there a way to avoid repetitive code like the following? Imaging 20 other functions taking mutable parameters with default values.
Everytime checking the argument for None, everytime assigning default value in if branch.
Putting the default in the function signature does not work as python caches the value the first time the function is called.
import datetime as dt
def dt_to_str(dtime: dt.datetime = None):
if dtime is None:
dtime = dt.datetime.now()
return dtime.strftime("%c")
if __name__ == '__main__':
print(dt_to_str())
I think in most cases, the if arg is None: arg = ... syntax is the best solution. But if you are really bothered by it, here's a decorator which works for single-argument functions:
from functools import wraps
def default_argument(arg_factory):
def decorator(f):
#wraps(f)
def wrapped(arg=None):
if arg is None:
arg = arg_factory()
return f(arg)
return wrapped
return decorator
Usage examples below: you can either pass a reference to an existing function, or a lambda.
import datetime as dt
#default_argument(dt.datetime.now)
def dt_to_str(dtime):
return dtime.strftime('%c')
print(dt_to_str())
# Mon Oct 25 00:16:03 2021
#default_argument(lambda: [])
def thing_with_list(lst):
return lst + [123]
print(thing_with_list())
# [123]

Mock the input() in the module body

I've read a lot of materials, but nothing helped. I tried to write some unit tests using pytest and faced the following problem: i can mock the input() inside the function i want to test (using #mock.patch or monkeypatch.setattr for builtins.input).
This is the code in my module:
def double():
a = input()
return int(a) * 2
And this is my test file:
# #mock.patch('builtins.input', return_value='13')
def testing(monkeypatch):
monkeypatch.setattr('builtins.input', lambda: "13")
assert double() == 26
But when i have input() in the body of my module i get the error - OSError: pytest: reading from stdin while output is captured! Consider using -s.
Example:
def double(a):
return int(a) * 2
x = input()
I can fix this with adding if __name__ == "__main__" before x = input(), but i'm curious if i can solve this in any other way. Thank you for your help in advance!

unit test in python for function that has no return value

I have a function that should pick only top 10 requests from list of requests:
def prioritize_top_10_requests(list_of_requests):
if not list_of_requests:
system.exit(1)
else:
for i in list_of_requests[0:10]:
print i
I want to write a unit test for this function just to check if 'i' is printed 10 times only though we have more list of requests.
I am writing python unit test cases for the first time.
I don't have python3 set up. The below code works with Python 3.
What it does is the following.
Created a UnitTest TestCase with one test, "test_priority".
In the test, redirect the stdout to a string.
Then execute the function.
Collect the print results from the string.
Remove None and empty strings and find the length.
Check if it is equal to 10.
import unittest
from io import StringIO
import sys
def prioritize_top_10_requests(list_of_requests):
for i in list_of_requests[0:10]:
print(i)
class TestMyCode(unittest.TestCase):
def test_priority(self):
sys.stdout = result = StringIO()
prioritize_top_10_requests(range(100))
sys.stdout = sys.__stdout__
printed_lines = result.getvalue()
print_count = len(printed_lines.strip().split('\n'))
self.assertEqual(print_count, 10)
if __name__ == '__main__':
unittest.main()

mock `readlines()` in python unit tests

I am trying to mock a readlines() object in python unit tests. What I have so far is
class Sample:
def read_file(filename):
with open(filename, "r") as f:
lines = f.readlines()
I want to write a unit test for readlines() object.
So far, I have come up with the following.
TEST_DATA = "test\ntest2\n"
#mock.patch("builtins.open")
def test_open(mock_open):
mock_open.side_effect = [mock_open(read_data=TEST_DATA).return_value]
assert mock_open.side_effect == Sample.read_file()
My question here is, how do I assert the returned value of mock_open is the same as the returned value of the actual read_file function in the Sample class? This is where I am failing and not able to go any further. Any help on this is much appreciated! Thank you in advance!
In unittest.mock docs there is an example that may help you
Here is the docs example adapted to your code.
from unittest.mock import patch
class Sample:
def read_file(filename):
with open(filename, "r") as f:
lines = f.readlines()
return lines
TEST_DATA = "test\ntest2\n"
def test_open(mock_open):
with patch('__main__.open', mock_open(read_data=TEST_DATA)) as m:
s = Sample()
res = s.read_file('foo')
assert res == TEST_DATA

Mocking a while statment Python

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"""

Resources