<html>
  <head>
    <meta content="text/html; charset=ISO-8859-1"
      http-equiv="Content-Type">
  </head>
  <body text="#000000" bgcolor="#FFFFFF">
    On 1/16/14 5:40 AM, James Chapman wrote:<br>
    <blockquote
cite="mid:CAHvkzy=ghCOm-EV158ct0DhGZtprKy4h-93uMBhdt59ZF5yPAQ@mail.gmail.com"
      type="cite">
      <div dir="ltr">
        <div class="gmail_quote">Originally sent to python tutor mailing
          list but I suspect this might be a better list for my
          question...<br>
          <br>
          <div dir="ltr">
            <div>Hi all<br>
            </div>
            <div dir="ltr">
              <div><br>
              </div>
              <div>
                I have a question regarding mocking in unit testing.</div>
              <div><br>
              </div>
              <div>Let's assume I have the following class:</div>
              <div><br>
              </div>
              <div><font face="courier new, monospace">-------------------------------------------</font></div>
              <div><font face="courier new, monospace">import subprocess<br>
                </font></div>
              <div><font face="courier new, monospace"><br>
                </font></div>
              <div>
                <div><font face="courier new, monospace">class
                    Pinger(object):</font></div>
                <div><font face="courier new, monospace"><br>
                  </font></div>
                <div><font face="courier new, monospace">&nbsp; &nbsp; def
                    ping_host(self, host_to_ping):</font></div>
                <div><font face="courier new, monospace">&nbsp; &nbsp; &nbsp; &nbsp;
                    cmd_string = 'ping %s' % (host_to_ping)</font></div>
                <div><font face="courier new, monospace">&nbsp; &nbsp; &nbsp; &nbsp;
                    cmd_args = cmd_string.split()</font></div>
                <div><font face="courier new, monospace">&nbsp; &nbsp; &nbsp; &nbsp; proc =
                    subprocess.Popen(cmd_args, shell=True)</font></div>
                <div><font face="courier new, monospace">&nbsp; &nbsp; &nbsp; &nbsp;
                    proc.wait()</font></div>
                <div><font face="courier new, monospace">&nbsp; &nbsp; &nbsp; &nbsp; if
                    proc.returncode != 1:</font></div>
                <div><font face="courier new, monospace">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
                    raise Exception('Error code was: %d' %
                    (proc.returncode))</font></div>
              </div>
              <div>
                <div><font face="courier new, monospace"><br>
                  </font></div>
                <div><font face="courier new, monospace">-------------------------------------------</font></div>
                <div><br>
                </div>
                <div><br>
                </div>
                <div>In my unittest I don't want to run the ping
                  command, (It might not be available on the build
                  system) I merely want to check that a call to
                  subprocess.Popen is made and that the parameters are
                  what I expect?</div>
                <div><br>
                </div>
                <div>So far I have this, but it doesn't work and I
                  suspect it's way off!!</div>
                <div><br>
                </div>
                <div><br>
                </div>
                <div><font face="courier new, monospace">-------------------------------------------<br>
                  </font></div>
                <div>
                  <div><font face="courier new, monospace">import mock</font></div>
                  <div><font face="courier new, monospace">import
                      unittest</font></div>
                  <div><font face="courier new, monospace">from tutor_q
                      import Pinger</font></div>
                  <div>
                    <font face="courier new, monospace"><br>
                    </font></div>
                  <div><font face="courier new, monospace">class
                      Test_Pinger(unittest.TestCase):</font></div>
                  <div><font face="courier new, monospace"><br>
                    </font></div>
                  <div><font face="courier new, monospace">&nbsp; &nbsp; def
                      test_ping_host(self):</font></div>
                  <div><font face="courier new, monospace">&nbsp; &nbsp; &nbsp; &nbsp;
                      pinger = Pinger()</font></div>
                  <div><font face="courier new, monospace">&nbsp; &nbsp; &nbsp; &nbsp;
                      assert pinger</font></div>
                  <div><font face="courier new, monospace">&nbsp; &nbsp; &nbsp; &nbsp;
                      subprocess = mock.Mock()</font></div>
                  <div><font face="courier new, monospace">&nbsp; &nbsp; &nbsp; &nbsp;
                      subprocess.Popen.return_value = 0</font></div>
                  <div><font face="courier new, monospace">&nbsp; &nbsp; &nbsp; &nbsp;
                      subprocess.assert_called_once_with(['ping','localhost'])</font></div>
                  <div><font face="courier new, monospace">&nbsp; &nbsp; &nbsp; &nbsp;
                      pinger.ping_host('127.0.0.1')</font></div>
                  <div><font face="courier new, monospace"><br>
                    </font></div>
                </div>
              </div>
            </div>
          </div>
        </div>
      </div>
    </blockquote>
    Often the trickiest thing about mocking is mocking the right name.&nbsp;
    Here you've created a mock, and it's assigned to a local variable
    named subprocess.&nbsp; This name is not related to the global subprocess
    name in the tutor_q module, which is the name that will be used by
    your pinger object.<br>
    <br>
    You have to assign to that global.&nbsp; A module's globals are also
    available as attributes on the module object, so you can do it like
    this:<br>
    <br>
    <font face="courier new, monospace"><br>
    </font>
    <div>
      <div><font face="courier new, monospace">import mock</font></div>
      <div><font face="courier new, monospace">import unittest</font></div>
      <div><font face="courier new, monospace">import tutor_q<br>
        </font></div>
      <div>
        <font face="courier new, monospace"><br>
        </font></div>
      <div><font face="courier new, monospace">class
          Test_Pinger(unittest.TestCase):</font></div>
      <div><font face="courier new, monospace"><br>
        </font></div>
      <div><font face="courier new, monospace">&nbsp; &nbsp; def
          test_ping_host(self):</font></div>
      <div><font face="courier new, monospace">&nbsp; &nbsp; &nbsp; &nbsp; pinger =
          tutor_q.Pinger()</font></div>
      <div><font face="courier new, monospace">&nbsp; &nbsp; &nbsp; &nbsp; assert pinger</font></div>
      <div><font face="courier new, monospace">&nbsp; &nbsp; &nbsp; &nbsp; subprocess =
          mock.Mock()</font></div>
      <div><font face="courier new, monospace">&nbsp; &nbsp; &nbsp; &nbsp;
          subprocess.Popen.return_value = 0</font></div>
      <div><font face="courier new, monospace">&nbsp; &nbsp; &nbsp; &nbsp;
          tutor_q.subprocess = subprocess</font><font face="courier new,
          monospace"><br>
          &nbsp; &nbsp; &nbsp; &nbsp; pinger.ping_host('127.0.0.1')</font></div>
    </div>
    <font face="courier new, monospace"><font face="courier new,
        monospace">&nbsp; &nbsp; &nbsp; &nbsp; </font>subprocess.assert_called_once_with(['ping','localhost'])</font>
    <br>
    <br>
    I've also moved the assert to after the code under test, since
    that's when the calls will be available to make assertions about. (I
    didn't actually test this code, if I got it wrong, someone on the
    list will school me!)<br>
    <br>
    A problem with this code is that you replace tutor_q.subprocess with
    a mock, but you don't restore it when the test is done.&nbsp; Mock has
    tools that can do this for you:<br>
    <br>
    <div><font face="courier new, monospace"><br>
      </font></div>
    <div><font face="courier new, monospace">&nbsp; &nbsp; def
        test_ping_host(self):</font></div>
    <div><font face="courier new, monospace">&nbsp; &nbsp; &nbsp; &nbsp; pinger =
        tutor_q.Pinger()</font></div>
    <div><font face="courier new, monospace">&nbsp; &nbsp; &nbsp; &nbsp; assert pinger</font></div>
    <div><font face="courier new, monospace">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; with
        mock.patch("tutor_q.subprocess") as subprocess:<br>
        &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; subprocess = mock.Mock()</font></div>
    <div><font face="courier new, monospace">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
        subprocess.Popen.return_value = 0</font></div>
    <div><font face="courier new, monospace">&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </font><font
        face="courier new, monospace">pinger.ping_host('127.0.0.1')</font></div>
    <font face="courier new, monospace"><font face="courier new,
        monospace">&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </font>subprocess.assert_called_once_with(['ping','localhost'])</font>
    <br>
    <br>
    Note that there is an unfortunate coupling of your test code and
    product code: the test had to know how subprocess was imported.&nbsp; In
    tutor_q.py, if you had instead used "from subprocess import Popen",
    then your mock would have to be similarly adjusted to mock
    tutor_q.Popen instead of tutor_q.subprocess.<br>
    <br>
    --Ned.<br>
    <blockquote
cite="mid:CAHvkzy=ghCOm-EV158ct0DhGZtprKy4h-93uMBhdt59ZF5yPAQ@mail.gmail.com"
      type="cite">
      <div dir="ltr">
        <div class="gmail_quote">
          <div dir="ltr">
            <div dir="ltr">
              <div>
                <div>
                  <div>
                    <font face="courier new, monospace"><br>
                    </font></div>
                  <div><font face="courier new, monospace"><br>
                    </font></div>
                  <div><font face="courier new, monospace">if __name__
                      == '__main__':</font></div>
                  <div><font face="courier new, monospace">&nbsp; &nbsp;
                      unittest.main()</font></div>
                </div>
                <div><font face="courier new, monospace"><br>
                  </font></div>
                <div><font face="courier new, monospace">-------------------------------------------</font><br>
                </div>
                <div><br>
                </div>
                <div><br>
                </div>
                <div>Can anyone point me in the right direction on how
                  to mock up these subprocess calls?</div>
                <div><br>
                </div>
                <div>Thanks</div>
                <span class="HOEnZb"><font color="#888888">
                    <div><br>
                    </div>
                    <div>James</div>
                    <div><br>
                    </div>
                    <div><br>
                    </div>
                    <div><br>
                    </div>
                  </font></span></div>
            </div>
          </div>
        </div>
        <br>
      </div>
      <br>
      <fieldset class="mimeAttachmentHeader"></fieldset>
      <br>
      <pre wrap="">_______________________________________________
testing-in-python mailing list
<a class="moz-txt-link-abbreviated" href="mailto:testing-in-python@lists.idyll.org">testing-in-python@lists.idyll.org</a>
<a class="moz-txt-link-freetext" href="http://lists.idyll.org/listinfo/testing-in-python">http://lists.idyll.org/listinfo/testing-in-python</a>
</pre>
    </blockquote>
    <br>
  </body>
</html>