Reputation: 5877
Suppose I have two files main.py
and test_main.py
. The contents of main.py
are:
import os
print('script running', os.getcwd())
The contents of test_main.py
are:
import pytest
import main
Running pytest -s
returns the following:
================================================= test session starts ==================================================
platform linux -- Python 3.8.6, pytest-6.2.3, py-1.10.0, pluggy-0.13.1
rootdir: /home/example_mocking
plugins: dash-1.20.0, anyio-2.2.0
collecting ... script running /home/example_mocking
collected 0 items
================================================ no tests ran in 0.01s =================================================
Now suppose main.py
has been provided to me by somebody else and I would prefer not to modify it until I achieve full test coverage. However, I would like to modify the behavior of os.getcwd()
such that it returns "Hello" as opposed to my current working directory.
Is there a way of mocking the behavior of os
without modifying main.py
such that when I run pytest -s
the following displays?
================================================= test session starts ==================================================
platform linux -- Python 3.8.6, pytest-6.2.3, py-1.10.0, pluggy-0.13.1
rootdir: /home/example_mocking
plugins: dash-1.20.0, anyio-2.2.0
collecting ... script running Hello
collected 0 items
================================================ no tests ran in 0.01s =================================================
Upvotes: 0
Views: 649
Reputation: 69914
I would recommend refactoring your script such that it does not perform side-effects on import -- these will be very difficult to patch and test properly without pollution.
Here's an adjusted setup which still functions, but is much more testable (you can find more about this technique in a video I put together here: python cli tested with pytest)
# main.py
import os
def main() -> int:
print('script running', os.getcwd())
return 0
if __name__ == '__main__':
raise SystemExit(main())
# main_test.py
import os
from unittest import mock
import main
def test_main_prints_cwd(capsys):
# can adjust what `getcwd` returns
with mock.patch.object(os, 'getcwd', return_value='Hello'):
assert main.main() == 0 # can test the return value of your program
# can test what your program prints
out, err = capsys.readouterr()
assert out == 'script running Hello\n'
assert err == ''
Upvotes: 1