[Tutor] Mocking with "mock" in unit testing

James Chapman james at uplinkzero.com
Fri Jan 17 12:18:48 CET 2014


Erm...?

CPython yeah.

If I rename "pinger.py" to "tutor.py" and change the unittest it runs fine.
Why?


-------------------------
import mock
import unittest
import tutor

class Test_Pinger(unittest.TestCase):

    def test_ping_host_succeeds(self):
        pinger = tutor.Pinger()
        with mock.patch("tutor.subprocess") as subprocess:
            subprocess.Popen.return_value.returncode = 0
            pinger.ping_host('localhost')
            subprocess.Popen.assert_called_once_with(['ping','localhost'],
shell=True)


    def test_ping_host_fails_and_throws_exception(self):
        pinger = tutor.Pinger()
        with mock.patch('tutor.subprocess') as subprocess:
            subprocess.Popen.return_value.returncode = 1
            self.assertRaises(Exception, pinger.ping_host, 'localhost')



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


--
James


On 17 January 2014 10:50, eryksun <eryksun at gmail.com> wrote:

> On Fri, Jan 17, 2014 at 4:58 AM, James Chapman <james at uplinkzero.com>
> wrote:
> > import mock
> > import unittest
> > import pinger
> >
> > class Test_Pinger(unittest.TestCase):
> >
> >     def test_ping_host_succeeds(self):
> >         pinger = pinger.Pinger()
>
> Are you using CPython? That raises an UnboundLocalError. Take a look
> at the CPython bytecode:
>
>     def test(self):
>         pinger = pinger.Pinger()
>
>     >>> dis.dis(test)
>       2           0 LOAD_FAST                1 (pinger)
>                   3 LOAD_ATTR                0 (Pinger)
>                   6 CALL_FUNCTION            0
>                   9 STORE_FAST               1 (pinger)
>                  12 LOAD_CONST               0 (None)
>                  15 RETURN_VALUE
>
> Notice LOAD_FAST(1), where fast local 1 is the local variable
> `pinger`. The value isn't assigned yet, and LOAD_FAST doesn't search
> globals and builtins. You need a unique name for the instance, such as
> `test_pinger`. Then the compiler knows to use LOAD_GLOBAL:
>
>     def test(self):
>         test_pinger = pinger.Pinger()
>
>     >>> dis.dis(test)
>       2           0 LOAD_GLOBAL              0 (pinger)
>                   3 LOAD_ATTR                1 (Pinger)
>                   6 CALL_FUNCTION            0
>                   9 STORE_FAST               1 (test_pinger)
>                  12 LOAD_CONST               0 (None)
>                  15 RETURN_VALUE
>
> Here's a version using a decorator instead:
>
>     @mock.patch('pinger.subprocess')
>     def test_ping_host_succeeds(self, subprocess):
>         subprocess.Popen.return_value.returncode = 0
>         test_pinger = pinger.Pinger()
>         test_pinger.ping_host('localhost')
>         subprocess.Popen.assert_called_once_with(['ping','localhost'],
>                                                  shell=True)
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.python.org/pipermail/tutor/attachments/20140117/1603996d/attachment.html>


More information about the Tutor mailing list