[TIP] Is this the best way to mock out a call to with open('foo') as f?

W. Matthew Wilson matt at tplus1.com
Sat Oct 2 13:34:05 PDT 2010


I'm using the mock package version 7.  Here's the production code I
want to test:

    def to_html(self, filepath):
        """
        Write this bag out as HTML to a file at filepath.
        """

        with open(os.path.join(filepath, self.html_filename), 'w') as f:
            f.write(self.html)

And here's the test for that to_html method.  I'm using mock.patch to
substitute a MagicMock object in for the results of the call to
open(...).

    @mock.patch(
        '__builtin__.open',
        mock.Mock(return_value=mock.MagicMock(spec=file)))
    def test_to_html():

        global b
        b.to_html('bogus filepath')

It took me a long time to figure out how to do this.  And that makes
me think maybe there's a much simpler and cleaner approach out there.

My example is different than the one in the documentation
(http://www.voidspace.org.uk/python/mock/magicmock.html) because that
one looks like this:

>>> from mock import Mock
>>> mock = Mock()
>>> mock.__enter__ = Mock()
>>> mock.__exit__ = Mock()
>>> mock.__exit__.return_value = False
>>> with mock:
...     pass

In that one, mock needs to support calls to __enter__ and __exit__.

where this one is mine:

    with open(...) as f:

In mine, the open function needs to return something that can support
calls to __enter__ and __exit__.

So, that's why I'm making a regular mock.Mock object that then returns
a fancy mock.MagicMock(spec=file) object.

Like I said, it took me a long time to figure this out, and I find it
confusing to read, so I hope there's some more elegant solution out
there.

Great library, by the way.

Matt


-- 
W. Matthew Wilson
matt at tplus1.com
http://tplus1.com



More information about the testing-in-python mailing list