I'm trying to assert all paths that passed through os.makedirs
to test that a folder structured has been created. The code isn't complicated and I'm sure it works find but my test reports that the method wasn't called with the paths I'm passing by checking calls in assert_any_call(my_path, 511)
. Now, what's weird in this case is that running assert_called_once
as a hack to see the output shows that the method was actually called with the expected paths. What's going wrong in this case? I wouldn't like to leave this part of my code untested since another dev could work on it an might fall in the trap of double-checking it and waste his/her time.
Code
def generate_base_folders():
if not os.path.exists(Path.cwd() / "unity_project"):
raise FolderCreationException("unity_project folder doesn't exist in the project")
for category in ["characters", "environments", "ui", "cinematics"]:
for tag in ["concept", "model", "animation", "vfx", "sfx", "vo", "music"]:
os.makedirs(Path.cwd() / "sessions" / category / "common" / tag)
os.makedirs(Path.cwd() / "unity_project" / "Assets" / category / "common" / tag)
Test
@patch("os.makedirs")
def test_base_folders(self, mkdirs_mock):
assertions = []
for category in ["characters", "environments", "ui", "cinematics"]:
for tag in ["concept", "model", "animation", "vfx", "sfx", "vo", "music"]:
assertions.append(Path.cwd() / "sessions" / category / "common" / tag)
assertions.append(
Path.cwd() / "unity_project" / "Assets" / category / "common" / tag
)
sessions.generate_base_folders()
for a in assertions:
mkdirs_mock.assert_any_call(a, 511)
assert_any_call traceback
Fss.
======================================================================
FAIL: test_base_folders (sessions.tests.sessions_tests.TestSessionsSetup.test_base_folders)
----------------------------------------------------------------------
Traceback (most recent call last):
File "C:\Users\juank\AppData\Local\Programs\Python\Python313\Lib\unittest\mock.py", line 1424, in patched
return func(*newargs, **newkeywargs)
File "C:\Users\juank\dev\projects\python\gamedev_eco\sessions\tests\sessions_tests.py", line 40, in test_base_folders
mkdirs_mock.assert_any_call(a, 511)
~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^
File "C:\Users\juank\AppData\Local\Programs\Python\Python313\Lib\unittest\mock.py", line 1048, in assert_any_call
raise AssertionError(
'%s call not found' % expected_string
) from cause
AssertionError: makedirs(WindowsPath('C:/Users/juank/gamedev_eco/sessions/characters/common/concept'), 511) call not found
----------------------------------------------------------------------
Ran 4 tests in 0.018s
FAILED (failures=1, skipped=2)
assert_called_once traceback
Fss.
======================================================================
FAIL: test_base_folders (sessions.tests.sessions_tests.TestSessionsSetup.test_base_folders)
----------------------------------------------------------------------
Traceback (most recent call last):
File "C:\Users\juank\AppData\Local\Programs\Python\Python313\Lib\unittest\mock.py", line 1424, in patched
return func(*newargs, **newkeywargs)
File "C:\Users\juank\dev\projects\python\gamedev_eco\sessions\tests\sessions_tests.py", line 40, in test_base_folders
mkdirs_mock.assert_called_once()
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^
File "C:\Users\juank\AppData\Local\Programs\Python\Python313\Lib\unittest\mock.py", line 956, in assert_called_once
raise AssertionError(msg)
AssertionError: Expected 'makedirs' to have been called once. Called 56 times.
Calls: [call(WindowsPath('C:/Users/juank/gamedev_eco/sessions/characters/common/concept')),
(truncated the list for brevity)
There is a little, math, bug in your code!
As your method has 2 for
, nested, it need to execute the task of the second for
for every item in this for (["concept", "model", "animation", "vfx", "sfx", "vo", "music"]
), 7 items, as many times as has items in your first for
(["characters", "environments", "ui", "cinematics"]
), 4 items.
It is a cartesian product, them 4 x 7 = 28. But you run the task of creation of dir twice
os.makedirs(Path.cwd() / "sessions" / category / "common" / tag)
os.makedirs(Path.cwd() / "unity_project" / "Assets" / category / "common" / tag)
So, as 28 + 28 = 56, the test is right (the assertion is wrong)!
Perhaps you want to test a more complete scenario, that may have more items or more contexts, but then you should review your code/tests.