Skip to content

Instantly share code, notes, and snippets.

@JensRantil
Created August 11, 2012 10:03
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save JensRantil/3323323 to your computer and use it in GitHub Desktop.
Save JensRantil/3323323 to your computer and use it in GitHub Desktop.
How to check if all files were closed using Mock
import mock
files_opened = []
real_open = open # Needed since I will wrap open
def open_wrapper(*args, **kw):
opened_file = mock.MagicMock(wraps=real_open(*args, **kw))
files_opened.append(opened_file)
return opened_file
open_mock = mock.MagicMock(side_effect=open_wrapper)
open_mock.__enter__.side_effect = open_wrapper
with mock.patch('__builtin__.open', open_mock, create=True):
import myapplication
myapplication.run()
for opened_file in files_opened:
opened_file.close.assert_called_once_with()
@has207
Copy link

has207 commented Aug 12, 2012

Interesting idea, I gave it a go with current version of flexmock. Ideally it could be much more elegant and short, but as flexmock doesn't have a built-in way to proxy for a builtin object it's arguably even more cumbersome than the Mock version. It avoids the need to globally track open files and doing the manual verification at the end, but the initial setup feels brittle and isn't very intuitive. I'll consider adding this use-case though, so could turn into one-liner using flexmock in the future..

from flexmock import flexmock
import unittest

real_open = open
def open_wrapper(name, mode, buffering=1):
  """this should really be a one-liner, but at the moment
  flexmock doesn't have a good way to wrap a builtin object so
  we need to manually  proxy all the regular API calls to the real file object.

  Ideally we should be able to do this:
  flexmock(__builtins__, open=lambda *k, **kw: flexmock(real_open(*k, *kw).should_call('close').once.mock))
  """
  fake_f = flexmock()
  f = real_open(name, mode, buffering)
  for attr in dir(f):
    if not attr.startswith('__') and not attr.endswith('__'):
      setattr(fake_f, attr, getattr(f, attr))
  flexmock(fake_f).should_call('close').once
  return fake_f

class TestOpen(unittest.TestCase):
  def test_open(self):
    flexmock(__builtins__, open=open_wrapper)
    f = open('/tmp/foo', 'r')
    f.readlines()
    f.close()

if __name__ == '__main__':
  unittest.main()

@JensRantil
Copy link
Author

@has207 Always fun to see it in another implementation. Seems like this is (currently) one of those things that are still a little clumsy. The things is, it's a highly useful test to catch all those file not closed. I am surprised this problem has surfaces before.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment