I need to know if Path.exists()
was called. I want to do that in a unittest but allways got the answer that it was not called.
I assume something is wrong with the import path. I know from the docs and some blog-posts that this can be tricky.
This is the "productive" code:
import pathlib
class Foo():
def __init__(self, file_path: pathlib.Path):
if not file_path.exists():
print('Not good.')
else:
print('Fine.')
And this is the unittest for it
import unittest
import unittest.mock
import pathlib
import mycode
class MyTest(unittest.TestCase):
@unittest.mock.patch('pathlib.Path')
def test_mycode(self, mock_path):
mypath = pathlib.Path('bar')
foo = mycode.Foo(mypath)
mock_path.exists.assert_called_once()
But the error is still
AssertionError: Expected 'exists' to have been called once. Called 0 times.
CodePudding user response:
You can create mock for pathlib.Path
using create_autospec helper function. And pass this mock object to the constructor of the Foo
class.
Functions or methods being mocked will have their arguments checked to ensure that they are called with the correct signature.
E.g. (Python 3.9.6)
foo.py
:
import pathlib
class Foo():
def __init__(self, file_path: pathlib.Path):
if not file_path.exists():
print('Not good.')
else:
print('Fine.')
foo_test.py
:
import unittest
import pathlib
from unittest.mock import create_autospec
from foo import Foo
class MyTest(unittest.TestCase):
def test_Foo_file_path_exists(self):
mock_path = create_autospec(pathlib.Path)
mock_path.exists.return_value = True
Foo(mock_path)
mock_path.exists.assert_called_once()
def test_Foo_file_path_not_exists(self):
mock_path = create_autospec(pathlib.Path)
mock_path.exists.return_value = False
Foo(mock_path)
mock_path.exists.assert_called_once()
if __name__ == '__main__':
unittest.main()
Test result:
Fine.
.Not good.
.
----------------------------------------------------------------------
Ran 2 tests in 0.184s
OK
Name Stmts Miss Cover Missing
----------------------------------------------------------------------
src/stackoverflow/71945781/foo.py 6 0 100%
src/stackoverflow/71945781/foo_test.py 17 0 100%
----------------------------------------------------------------------
TOTAL 23 0 100%
CodePudding user response:
The answer of @slideshowp2 is fine and working. And it pointed me to the right solution better fitting to my own MWE.
class MyTest(unittest.TestCase):
@unittest.mock.patch('pathlib.Path')
def test_mycode(self, mocked_path):
foo = mycode.Foo(mocked_path)
mocked_path.exists.assert_called_once()
The problem with my code was that I instantiated a real object of pathlib.Path
. But the key of the solution is to use the mock object mocked_path
because this is a surrogate for a real Path
object.
In my questions intial code the Foo.__init__()
never used the mocked object but the real pathlib.Path
.