<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>
    <meta content="text/html; charset=windows-1252"
      http-equiv="Content-Type">
    <title></title>
  </head>
  <body bgcolor="#ffffff" text="#000000">
    On 03/10/2010 01:48, Gregory P. Smith wrote:
    <blockquote
      cite="mid:AANLkTimFZqS1o6Gt9vEoVEWmDr7iQSScfc7XTAQJfq6Y@mail.gmail.com"
      type="cite"><br>
      <br>
      <div class="gmail_quote">On Sat, Oct 2, 2010 at 3:24 PM, Michael
        Foord <span dir="ltr">&lt;<a moz-do-not-send="true"
            href="mailto:fuzzyman@voidspace.org.uk">fuzzyman@voidspace.org.uk</a>&gt;</span>
        wrote:<br>
        <blockquote class="gmail_quote" style="margin: 0pt 0pt 0pt
          0.8ex; border-left: 1px solid rgb(204, 204, 204);
          padding-left: 1ex;">
          <div class="im"> On 02/10/2010 21:34, W. Matthew Wilson wrote:<br>
            <blockquote class="gmail_quote" style="margin: 0pt 0pt 0pt
              0.8ex; border-left: 1px solid rgb(204, 204, 204);
              padding-left: 1ex;">
              I'm using the mock package version 7.  Here's the
              production code I<br>
              want to test:<br>
              <br>
                  def to_html(self, filepath):<br>
                      """<br>
                      Write this bag out as HTML to a file at filepath.<br>
                      """<br>
              <br>
                      with open(os.path.join(filepath,
              self.html_filename), 'w') as f:<br>
                          f.write(self.html)<br>
              <br>
              And here's the test for that to_html method.  I'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>
                      '__builtin__.open',<br>
                      mock.Mock(return_value=mock.MagicMock(spec=file)))<br>
                  def test_to_html():<br>
              <br>
                      global b<br>
                      b.to_html('bogus filepath')<br>
              <br>
              It took me a long time to figure out how to do this.  And
              that makes<br>
              me think maybe there'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's particular nervousness about patching __builtin__ -
          the use of "patch" makes guarantees about when the patching
          will be done and undone so it won't affect any code run
          outside of the specific test.<br>
          <br>
          However, there is an alternative way. You could *just* patch
          the 'open' function in the module under test. Because 'open'
          won'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>
    </blockquote>
    <br>
    Cool. :-)<br>
    <br>
    <blockquote
      cite="mid:AANLkTimFZqS1o6Gt9vEoVEWmDr7iQSScfc7XTAQJfq6Y@mail.gmail.com"
      type="cite">
      <div class="gmail_quote">
        <div><br>
        </div>
        <div>I agree that dependency injection altering the public API
          is bad. For example I wouldn't do it for public APIs on the
          standard library.</div>
      </div>
    </blockquote>
    <br>
    But even internal APIs still need to be read / used by developers
    and I don't like screwing with them either. <br>
    <br>
    <blockquote
      cite="mid:AANLkTimFZqS1o6Gt9vEoVEWmDr7iQSScfc7XTAQJfq6Y@mail.gmail.com"
      type="cite">
      <div class="gmail_quote">
        <div><br>
        </div>
        <div>But buried within a code base in a project where it isn't
          exposed to outside users I don'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
          "protected by convention" additional parameter.  Adding your
          own mock open to the module global namespace is doing
          something similar but happily doesn't need code modifications
          to support the injection.</div>
      </div>
    </blockquote>
    <br>
    Right. My contention is that dependency injection *just* for
    testability is never *required* for Python and rarely preferable to
    other techniques. There are plenty of times when dependency
    injection is useful as a structure / architecture in its own right
    though.<br>
    <br>
    All the best,<br>
    <br>
    Michael Foord<br>
    <br>
    <br>
    <blockquote
      cite="mid:AANLkTimFZqS1o6Gt9vEoVEWmDr7iQSScfc7XTAQJfq6Y@mail.gmail.com"
      type="cite">
      <div class="gmail_quote">
        <div><br>
        </div>
        <div>-gps</div>
        <div><br>
        </div>
        <blockquote class="gmail_quote" style="margin: 0pt 0pt 0pt
          0.8ex; border-left: 1px solid rgb(204, 204, 204);
          padding-left: 1ex;">
          <br>
          with patch('the_module.open',
          Mock(return_value=MagicMock(spec=file)), create=True):<br>
          ...<br>
          <br>
          or even:<br>
          <br>
          @patch('module.open', 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: 0pt 0pt 0pt
              0.8ex; border-left: 1px solid rgb(204, 204, 204);
              padding-left: 1ex;">
              My example is different than the one in the documentation<br>
              (<a moz-do-not-send="true"
                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: 0pt 0pt 0pt
                0.8ex; border-left: 1px solid rgb(204, 204, 204);
                padding-left: 1ex;">
                <blockquote class="gmail_quote" style="margin: 0pt 0pt
                  0pt 0.8ex; border-left: 1px solid rgb(204, 204, 204);
                  padding-left: 1ex;">
                  <blockquote class="gmail_quote" style="margin: 0pt 0pt
                    0pt 0.8ex; border-left: 1px solid rgb(204, 204,
                    204); 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's why I'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'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 moz-do-not-send="true"
              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 class="h5">
              _______________________________________________<br>
              testing-in-python mailing list<br>
              <a moz-do-not-send="true"
                href="mailto:testing-in-python@lists.idyll.org"
                target="_blank">testing-in-python@lists.idyll.org</a><br>
              <a moz-do-not-send="true"
                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>
    </blockquote>
    <br>
    <br>
    <pre class="moz-signature" cols="72">-- 
<a class="moz-txt-link-freetext" href="http://www.voidspace.org.uk/blog">http://www.voidspace.org.uk/blog</a>

READ CAREFULLY. By accepting and reading this email you agree,
on behalf of your employer, to release me from all obligations
and waivers arising from any and all NON-NEGOTIATED agreements,
licenses, terms-of-service, shrinkwrap, clickwrap, browsewrap,
confidentiality, non-disclosure, non-compete and acceptable use
policies (”BOGUS AGREEMENTS”) that I have entered into with your
employer, its partners, licensors, agents and assigns, in
perpetuity, without prejudice to my ongoing rights and privileges.
You further represent that you have the authority to release me
from any BOGUS AGREEMENTS on behalf of your employer.
</pre>
  </body>
</html>