Reputation: 11357
I'm trying to test the following function:
def my_testable_function(input_filename):
if os.path.isfile(input_filename):
return "Exist!"
return "Not exist"
Here is my first effort to test the function above:
def test_1():
os.path.isfile = Mock(return_value=True)
result = my_testable_function("/existing/path/file.txt")
assert result == "Exist!"
Running with pytest==6.2.1 + pytest-cov==2.11.1:
$ py.test -v --ff --cov=<my_package> tests
I end up with INTERNALERROR:
====================================================================== test session starts =======================================================================
platform darwin -- Python 3.8.5, pytest-6.2.1, py-1.10.0, pluggy-0.13.1 -- /Users/my-user/my-project/venv/bin/python3
cachedir: .pytest_cache
rootdir: /Users/my-user/my-project
plugins: cov-2.11.1, aiohttp-0.3.0
collected 6 items
run-last-failure: no previously failed tests, not deselecting items.
tests/test_app.py::test_1 PASSED [100%]
INTERNALERROR> Traceback (most recent call last):
INTERNALERROR> File "/Users/my-user/my-project/venv/lib/python3.8/site-packages/_pytest/main.py", line 269, in wrap_session
INTERNALERROR> session.exitstatus = doit(config, session) or 0
INTERNALERROR> File "/Users/my-user/my-project/venv/lib/python3.8/site-packages/_pytest/main.py", line 323, in _main
INTERNALERROR> config.hook.pytest_runtestloop(session=session)
INTERNALERROR> File "/Users/my-user/my-project/venv/lib/python3.8/site-packages/pluggy/hooks.py", line 286, in __call__
INTERNALERROR> return self._hookexec(self, self.get_hookimpls(), kwargs)
INTERNALERROR> File "/Users/my-user/my-project/venv/lib/python3.8/site-packages/pluggy/manager.py", line 93, in _hookexec
INTERNALERROR> return self._inner_hookexec(hook, methods, kwargs)
INTERNALERROR> File "/Users/my-user/my-project/venv/lib/python3.8/site-packages/pluggy/manager.py", line 84, in <lambda>
INTERNALERROR> self._inner_hookexec = lambda hook, methods, kwargs: hook.multicall(
INTERNALERROR> File "/Users/my-user/my-project/venv/lib/python3.8/site-packages/pluggy/callers.py", line 203, in _multicall
INTERNALERROR> gen.send(outcome)
INTERNALERROR> File "/Users/my-user/my-project/venv/lib/python3.8/site-packages/pytest_cov/plugin.py", line 271, in pytest_runtestloop
INTERNALERROR> self.cov_controller.finish()
INTERNALERROR> File "/Users/my-user/my-project/venv/lib/python3.8/site-packages/pytest_cov/engine.py", line 44, in ensure_topdir_wrapper
INTERNALERROR> return meth(self, *args, **kwargs)
INTERNALERROR> File "/Users/my-user/my-project/venv/lib/python3.8/site-packages/pytest_cov/engine.py", line 230, in finish
INTERNALERROR> self.cov.stop()
INTERNALERROR> File "/Users/my-user/my-project/venv/lib/python3.8/site-packages/coverage/control.py", line 701, in combine
INTERNALERROR> combine_parallel_data(
INTERNALERROR> File "/Users/my-user/my-project/venv/lib/python3.8/site-packages/coverage/data.py", line 110, in combine_parallel_data
INTERNALERROR> new_data.read()
INTERNALERROR> File "/Users/my-user/my-project/venv/lib/python3.8/site-packages/coverage/sqldata.py", line 753, in read
INTERNALERROR> with self._connect(): # TODO: doesn't look right
INTERNALERROR> File "/Users/my-user/my-project/venv/lib/python3.8/site-packages/coverage/sqldata.py", line 298, in _connect
INTERNALERROR> self._open_db()
INTERNALERROR> File "/Users/my-user/my-project/venv/lib/python3.8/site-packages/coverage/sqldata.py", line 266, in _open_db
INTERNALERROR> self._read_db()
INTERNALERROR> File "/Users/my-user/my-project/venv/lib/python3.8/site-packages/coverage/sqldata.py", line 270, in _read_db
INTERNALERROR> with self._dbs[get_thread_id()] as db:
INTERNALERROR> File "/Users/my-user/my-project/venv/lib/python3.8/site-packages/coverage/sqldata.py", line 1037, in __enter__
INTERNALERROR> self._connect()
INTERNALERROR> File "/Users/my-user/my-project/venv/lib/python3.8/site-packages/coverage/sqldata.py", line 1019, in _connect
INTERNALERROR> self.con = sqlite3.connect(filename, check_same_thread=False)
INTERNALERROR> sqlite3.OperationalError: unable to open database file
Trying to do it with monkeypatch works (no INTERNALERROR
):
def mock_is_file(filename):
if filename == "/existing/path/file.txt":
return True
return os.path.isfile(filename)
def test_2(monkeypatch):
monkeypatch.setattr(os.path, 'isfile', mock_is_file)
my_testable_function("/existing/path/file.txt")
assert result == "Exist!"
My question is, why does it happen in my first try and why does it work in the second?
Upvotes: 0
Views: 1183
Reputation: 375922
When you put a mock in place, you have to also be sure to undo the mock when your test ends. You changed os.path.isfile in your test, and left it changed. Later, coverage needs that function, and gets your mock instead.
The monkeypatch approach works because the monkeypatch fixture automatically cleans up the mock when the test is done.
Upvotes: 1