[ Python: Returning tuple for os.walk in unittest ]
I am writing a unit test for the following function:
def create_zip(path,zipf): #Create zip files for root, dirs, files in os.walk(path): for file in files: #write all json files to a zip file for name in glob.glob('*.json'): os.chdir(root) #write files to zip file zipf.write(name) #Remove files after creating zip file os.remove(name)
This is what I have at the moment:
tmpfilepath = os.path.join(tempfile.gettempdir(), "tmp-testfile") @mock.patch('my_script.os.walk') def test_create_basic_zip(self,mock_os_walk): mock_os_walk.return_value = ('test1','test2','test3') zipf = zipfile.ZipFile(self.tmpfilepath, 'w', zipfile.ZIP_DEFLATED) files = my_script.create_zip('.',zipf)
However I keep getting the error:
for root, dirs, files in os.walk(path): ValueError: too many values to unpack
or when I change it to:
mock_os_walk.return_value = (['test1'],['test2'],['test3'])
I get the error:
ValueError: need more than 1 value to unpack
Where am I going wrong?
In order to match the
os.walk() result format, you need to have an iterable where each item consists of 3 elements - the
mock_os_walk.return_value = ('test1','test2','test3')
with, for example:
mock_os_walk.return_value = [('./test1', ['test2', 'test3'], ['test4.txt']), ]
Your mock of os.walk needs to return an iterable, since you are doing
for ... in os.walk(...):
It turns out that a tuple is an iterable. So when you set
...mock.return_value = (...) you are defining the iterable that will be returned.
os.walk, and get a tuple back. But you called it in the context of a
for loop, so effectively you have written:
for a,b,c in ('test1', 'test2', 'test3'):
Which expands to:
a,b,c = 'test1'
the first time through the loop.
What you really want is to provide an iterable that gives a value for each of the variables, at least once and possibly more. This code works, and I think you can figure out the rest:
#!python3 from unittest import mock import os def other_function(): for a,b,c in os.walk('.'): print(a,b,c) @mock.patch('os.walk') def test_code(mock_os_walk): mock_os_walk.return_value = ((1,2,3), (4,5,6), (7,8,9)) other_function() test_code()