0

As a follow up to a previous question I would like to have a mock open function in a separate file be able to use the builtin open function. Again, here are the files:

main.py
mock.py
test.txt
test_main.py

main.py contains the following:

fs = open('test.txt', 'r')

mock.py now contains the following:

import builtins

def open(filename, mode):
  fs = builtins.open(filename, mode)
  print(fs.readline())
  fs.close()

test.txt contains the following:

abc
def
ghi

test_main.py contains the following:

import pathlib
import mock
import builtins

if __name__=="__main__":
  file_path = pathlib.Path('test.txt')
  builtins.open = mock.open
  import main

Unfortunately when I run python test_main.py I get the following error:

RecursionError: maximum recursion depth exceeded

Which indicates to me that mock.open is not using the built-in open in its body....

How do I mock open for main.py and all its imports, but have mock.open be able to use the built-in open?

user32882
  • 5,094
  • 5
  • 43
  • 82
  • 2
    You redefined `builtins.open` to an object that calls `builtins.open`. – chepner Mar 12 '22 at 15:41
  • Use `unittest.mock.patch` to patch the symbol `open` in `main.py`. – Samwise Mar 12 '22 at 15:43
  • 1
    Replacing `open` with something that not only opens the file, but reads a line from the file and immediately closes it seems like a bad idea. – chepner Mar 12 '22 at 15:44
  • Here's my issue... I have third party code which opens files without closing them. I need to test this code, and obviously my test teardown can't delete these generated files since they are not closed from within the third-party program. I need to somehow hijack `open` so I can temporarily get my test suite to work. – user32882 Mar 12 '22 at 15:44
  • The `unittest` library can very much be useful for writing `pytest` tests, yes. You can use any code you want with `pytest`. – Samwise Mar 12 '22 at 15:45
  • I use `pytest` to run tests without ever using the `pytest` module. I don't think there's any reason you couldn't use `unittest`'s functionality in a test that also uses stuff from the `pytest` module, but your test doesn't `import pytest` so I think that's moot anyway. – Samwise Mar 12 '22 at 15:48
  • The top answer of the linked dupe covers the appropriate use of `unittest.mock.patch` very nicely. – Samwise Mar 12 '22 at 15:50
  • @Samwise I tried with pytest and renamed the function in `mock.py`: `monkeypatch.setattr(builtins, "open", mock.mock_open)`. Still getting the same error regarding recursion depth... – user32882 Mar 12 '22 at 16:00
  • As I said, patch it in `main.py`, not in `mock.py`. – Samwise Mar 12 '22 at 16:02
  • `main.py` represents the client code, i.e. the code I'm testing... I can't/shouldn't be touching that. – user32882 Mar 12 '22 at 16:03
  • 1
    The point of `patch` is that you patch the code under test, from *inside your test*, without touching the actual file you're testing. Read the linked duplicate carefully, or google `unittest.mock.patch` and take a sec to read over how it works. – Samwise Mar 12 '22 at 16:05
  • And frankly, you aren't doing this to test the code so much as to work around a known bug in the 3rd-party code. – chepner Mar 12 '22 at 16:41
  • I'm of the opinion that third-party code should not be modified until fully covered by a test suite. – user32882 Mar 12 '22 at 16:46

0 Answers0