Reputation: 657
I am trying to mock Python os
module but my mocking steps are not working.
The code in the file os_mock.py:
import os
class MyTestMock:
def rm(self):
# some reason file is always hardcoded
file_path = "/tmp/file1"
if os.path.exists(file_path):
os.remove(file_path)
print(file_path, 'removed successfully')
else:
print(file_path, 'Does not exist')
The code in the test case file test_os_mock.py
import os
import unittest
from unittest.mock import patch
from os_mock import MyTestMock
class TestMyTestMock(unittest.TestCase):
@patch('os.path')
@patch('os.remove')
def test_rm(self, mock_remove, mock_path):
my_test_mock = MyTestMock()
mock_path.exists.return_vallue = False
my_test_mock.rm()
self.assertFalse(mock_remove.called)
mock_path.exists.return_vallue = True
my_test_mock.rm()
self.assertTrue(mock_remove.called)
I am getting below error when I execute test cases
F
======================================================================
FAIL: test_rm (__main__.TestMyTestMock)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/unittest/mock.py", line 1336, in patched
return func(*newargs, **newkeywargs)
File "/Users/vuser/code/MP-KT/mock/test_os_mock.py", line 15, in test_rm
self.assertFalse(mock_remove.called)
AssertionError: True is not false
----------------------------------------------------------------------
Ran 1 test in 0.008s
FAILED (failures=1)
I know I am doing something wrong while mocking, But I could not able to figure it out, I got couple of stack overflow links, I followed it, but no help.
Upvotes: 0
Views: 398
Reputation: 2548
I have made some change only to your test file, while the file os_mock.py
remains unchanged.
If you change return_vallue
to return_value
your test passes successfully so these changes (in the 2 points where the errors are present) are sufficient.
In particular the changes are the followings:
mock_path.exists.return_vallue=False
--> mock_path.exists.return_value=False
(return_vallue is not correct)mock_path.exists.return_vallue=True
--> mock_path.exists.return_value=True
(return_vallue is not correct)I have removed the import os
from the file test_os_mock.py
because the patch()
function operates on the script os_mock.py
and it is not necessary in the test file.
The test works with the import too but it is less clear!
assert_not_called
and assert_called_once
In my opinion the package unittest.mock
provides methods assert_not_called()
and assert_called_once()
who can improve your tests.
For example self.assertTrue(mock_remove.called)
ensures you called the mocked method, instead mock_remove.assert_called_once()
checks that you called the method exactly one time.
So I recommend the followings changes:
self.assertFalse(mock_remove.called)
--> mock_remove.assert_not_called()
self.assertTrue(mock_remove.called)
--> mock_remove.assert_called_once()
With the changes showed, the file test_os_mock.py becomes:
#import os # <--- I remove this import because patch operates on the file os_mock
import unittest
from unittest.mock import patch
from os_mock import MyTestMock
class TestMyTestMock(unittest.TestCase):
@patch('os.path')
@patch('os.remove')
def test_rm(self, mock_remove, mock_path):
my_test_mock = MyTestMock()
# return_vallue --> return_value
mock_path.exists.return_value = False
my_test_mock.rm()
mock_remove.assert_not_called()
#self.assertFalse(mock_remove.called)
# return_vallue --> return_value
mock_path.exists.return_value = True
my_test_mock.rm()
mock_remove.assert_called_once()
#self.assertTrue(mock_remove.called)
if __name__ == "__main__":
unittest.main()
assert_called_once_with
In your test case better than assert_called_once()
is the method assert_called_once_with()
which verifies the value of the argument passed to the method. With this other method your test becomes as follow:
@patch('os.path')
@patch('os.remove')
def test_rm(self, mock_remove, mock_path):
my_test_mock = MyTestMock()
mock_path.exists.return_value = False
my_test_mock.rm()
mock_remove.assert_not_called()
mock_path.exists.return_value = True
my_test_mock.rm()
# here is the NEW CHANGE
mock_remove.assert_called_once_with("/tmp/file1")
This link is very useful for understanding Mocking object in Python. It explains also the use of mock.patch()
function.
Upvotes: 3