My question is how to mock open in python, such that it reacts differently depending on the argument open() is called with. These are some different scenario's that should be possible:
-
open a mocked file; read preset contents, the basic scenario. This is already possible within the framework, I know.
with patch.object(__builtin__, 'open', mock_open(read_data='content')): with open('a') as handle: print handle.read() # output: content -
open two mocked files and have them give back different values for the read() method. Example code:
with patch.object(__builtin__, 'open', mock_open(side_effect)): with open('a') as handle: print handle.read() # output: content with open('b') as handle: print handle.read() # output: different!
The second example you could do by doing something similar as in the mock_open code in the mock.py. This, by changing the line in mock_open that reads:
handle.read.return_value = read_data
with something like:
handle.read.side_effect = my_side_effect
# where:
values = ['content', 'different!']
def my_side_effect():
return values.pop(0)
Okay, so that is not the issue either. However, what I want is the above except:
- The order in which the files read() methods have been called is irrelevant, what is relevant is the file name argument that was supplied when calling open. So if I would open file a, its
readmethod would always returncontent, while file b'sreadmethod would always returndifferent!regardless of the order in which they have been called. - Furthermore, if I call
open('actual_file.txt')to open an actual file, I want the actual file to be opened, and not a magic mock with mocked behavior.
To this effect I have written the following code:
from mock import MagicMock
from mock import patch
import __builtin__
values = {'a':1, 'b': 2, 'c':3}
def my_mock_open(original_open, read_data):
file_spec = file
def my_side_effect(arg):
if arg in values:
mock = MagicMock(name='open', spec=original_open)
handle = MagicMock(spec=file_spec)
handle.write.return_value = None
handle.__enter__.return_value = handle
handle.read.return_value = values[arg]
mock.return_value = handle
return mock
else:
return original_open(arg)
return_mock = MagicMock(name='open', spec=open)
return_mock.side_effect = my_side_effect
return return_mock
if __name__ == "__main__":
with patch.object(__builtin__, 'open', my_mock_open(open, values)):
with open('actual_file.txt') as handle:
print handle.read()
with open('a') as handle:
print handle.read()
This code works for actual_file.txt. However, when I try to open a file that I wish to mock, such as with the open('a') call. I get the following error.
Traceback (most recent call last):
Some text inside content.txt
File "D:/dev/python/scrap/src/main2.py", line 33, in <module>
with open('a') as handle:
AttributeError: __exit__
Process finished with exit code 1
I have tried adding a line to my_side_effect where such as:
handle.__exit__.return_value = None
# or even:
handle.__exit__ = MagicMock()
None of these seem to solve the problem however. Could anyone shed some light on the issue please?
Aucun commentaire:
Enregistrer un commentaire