<br><br><div class="gmail_quote">On Sat, Oct 2, 2010 at 3:24 PM, Michael Foord <span dir="ltr">&lt;<a href="mailto:fuzzyman@voidspace.org.uk">fuzzyman@voidspace.org.uk</a>&gt;</span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex;">

<div class="im"> On 02/10/2010 21:34, W. Matthew Wilson wrote:<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
I&#39;m using the mock package version 7.  Here&#39;s the production code I<br>
want to test:<br>
<br>
     def to_html(self, filepath):<br>
         &quot;&quot;&quot;<br>
         Write this bag out as HTML to a file at filepath.<br>
         &quot;&quot;&quot;<br>
<br>
         with open(os.path.join(filepath, self.html_filename), &#39;w&#39;) as f:<br>
             f.write(self.html)<br>
<br>
And here&#39;s the test for that to_html method.  I&#39;m using mock.patch to<br>
substitute a MagicMock object in for the results of the call to<br>
open(...).<br>
<br>
     @mock.patch(<br>
         &#39;__builtin__.open&#39;,<br>
         mock.Mock(return_value=mock.MagicMock(spec=file)))<br>
     def test_to_html():<br>
<br>
         global b<br>
         b.to_html(&#39;bogus filepath&#39;)<br>
<br>
It took me a long time to figure out how to do this.  And that makes<br>
me think maybe there&#39;s a much simpler and cleaner approach out there.<br>
<br>
</blockquote></div>
In principle I think that the way you patch __builtin__.open with a mock that returns a MagicMock is fine. To answer Gregory&#39;s particular nervousness about patching __builtin__ - the use of &quot;patch&quot; makes guarantees about when the patching will be done and undone so it won&#39;t affect any code run outside of the specific test.<br>


<br>
However, there is an alternative way. You could *just* patch the &#39;open&#39; function in the module under test. Because &#39;open&#39; won&#39;t exist in that namespace as an explicit name you will have to use the create keyword argument to patch:<br>

</blockquote><div><br></div><div>Hmm, I am more comfortable with that approach.</div><div><br></div><div>I agree that dependency injection altering the public API is bad. For example I wouldn&#39;t do it for public APIs on the standard library.</div>

<div><br></div><div>But buried within a code base in a project where it isn&#39;t exposed to outside users I don&#39;t mind so much.  There are also other dep. injection styles such as adding private attributes or methods to your class for the things you want to inject at test time rather than my simple example of a _ prefixed &quot;protected by convention&quot; additional parameter.  Adding your own mock open to the module global namespace is doing something similar but happily doesn&#39;t need code modifications to support the injection.</div>

<div><br></div><div>-gps</div><div><br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex;">
<br>
with patch(&#39;the_module.open&#39;, Mock(return_value=MagicMock(spec=file)), create=True):<br>
...<br>
<br>
or even:<br>
<br>
@patch(&#39;module.open&#39;, create=True)<br>
def the_test(mock_open):<br>
mock_open.return_value = MagicMock(spec=file)<br>
<br>
All the best,<br><font color="#888888">
<br>
Michael Foord</font><div class="im"><br>
<br>
<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
My example is different than the one in the documentation<br>
(<a href="http://www.voidspace.org.uk/python/mock/magicmock.html" target="_blank">http://www.voidspace.org.uk/python/mock/magicmock.html</a>) because that<br>
one looks like this:<br>
<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">


from mock import Mock<br>
mock = Mock()<br>
mock.__enter__ = Mock()<br>
mock.__exit__ = Mock()<br>
mock.__exit__.return_value = False<br>
with mock:<br>
</blockquote></blockquote></blockquote>
...     pass<br>
<br>
In that one, mock needs to support calls to __enter__ and __exit__.<br>
<br>
where this one is mine:<br>
<br>
     with open(...) as f:<br>
<br>
In mine, the open function needs to return something that can support<br>
calls to __enter__ and __exit__.<br>
<br>
So, that&#39;s why I&#39;m making a regular mock.Mock object that then returns<br>
a fancy mock.MagicMock(spec=file) object.<br>
<br>
Like I said, it took me a long time to figure this out, and I find it<br>
confusing to read, so I hope there&#39;s some more elegant solution out<br>
there.<br>
<br>
Great library, by the way.<br>
Matt<br>
<br>
<br>
</blockquote>
<br>
<br>
-- <br>
</div><div class="im"><a href="http://www.voidspace.org.uk/blog" target="_blank">http://www.voidspace.org.uk/blog</a><br>
<br>
READ CAREFULLY. By accepting and reading this email you agree,<br>
on behalf of your employer, to release me from all obligations<br>
and waivers arising from any and all NON-NEGOTIATED agreements,<br>
licenses, terms-of-service, shrinkwrap, clickwrap, browsewrap,<br>
confidentiality, non-disclosure, non-compete and acceptable use<br>
policies (”BOGUS AGREEMENTS”) that I have entered into with your<br>
employer, its partners, licensors, agents and assigns, in<br>
perpetuity, without prejudice to my ongoing rights and privileges.<br>
You further represent that you have the authority to release me<br>
from any BOGUS AGREEMENTS on behalf of your employer.<br>
<br>
<br></div><div><div></div><div class="h5">
_______________________________________________<br>
testing-in-python mailing list<br>
<a href="mailto:testing-in-python@lists.idyll.org" target="_blank">testing-in-python@lists.idyll.org</a><br>
<a href="http://lists.idyll.org/listinfo/testing-in-python" target="_blank">http://lists.idyll.org/listinfo/testing-in-python</a><br>
</div></div></blockquote></div><br>