4

I'm trying to learn Python and mocking infrastructure in Python at the same time (Due to requirement at my work place). I should also mention that I'm also not familiar with mocking feature in C++ or any other language.

So far, from what I've understood is that, with mocking, I can exercise the application code that makes OS. networking etc related calls, without actually invoking those operation.

Let's say I've an application, implemented as network.py

#!/usr/bin/env python

import sys
import socket

class NetworkService(object):
    def sock_create(self):
        try:
            s = socket.socket()
            s.close()
            print "closed socket"
        except Exception, err:    
            print "error creating socket"
            sys.exit(1) 

Things that I'd like to achieve with my unit test is:

  1. Make sure that both normal and failure paths get tested.

In this case, to achieve, this I'm trying to come up with a sample unit test case that exercises the sock_create method, as below:

#!/usr/bin/env python

import unittest
import mock
from network import NetworkService

class NetworkServiceTest(unittest.TestCase):
    @mock.patch('network.socket')
    def test_01_sock_create(self, mock_sock):
        reference = NetworkService()
        mock_sock.return_value = False
        # NetworkService::sock_create::s.close() should NOT get called  
        reference.sock_create()
        self.assertFalse(mock_sock.close.called, "Failed to not call close")

        mock_sock.socket.return_value = True
        # NetworkService::sock_create::s.close() should get called
        reference.sock_create()
        # how to test this ???
        #mock_sock.close.assert_called_with("")

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

As you can see above, the last 'assert' statement is currently commented out; I'm not sure, how to check this? The following gives me error:

#!/usr/bin/env python

import unittest
import mock
from network import NetworkService

class NetworkServiceTest(unittest.TestCase):
    @mock.patch('network.socket')
    def test_01_sock_create(self, mock_sock):
        reference = NetworkService()
        mock_sock.return_value = False
        reference.sock_create()
        self.assertFalse(mock_sock.close.called, "Failed to not call close")

        mock_sock.socket.return_value = True
        reference.sock_create()
        self.assertTrue(mock_sock.close.called, "Should have called s.close")

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

and the error:

$ python tester.py
F
======================================================================
FAIL: test_01_sock_create (__main__.NetworkServiceTest)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/usr/lib/python2.7/site-packages/mock/mock.py", line 1305, in patched
    return func(*args, **keywargs)
  File "tester.py", line 17, in test_01_sock_create
    self.assertTrue(mock_sock.close.called, "Should have called s.close")
AssertionError: Should have called s.close

----------------------------------------------------------------------
Ran 1 test in 0.002s

FAILED (failures=1)
closed socket
error creating socket

NOTE that I'm using mocking in Python 2.7 (mock need to be installed as a separate module)

1

1 Answer 1

1

In network.py you are printing out a string. If you instead would print out the actual error you would see the reason why it's failing. What you would see in this case is that it's failing because of an AttributeError. AttributeError("'bool' object has no attribute 'close'",)

The reason this is happening is because you're giving the mock object the return value of True or False. Since a bool doesn't have any open or close method it'll throw that error.

A few other tips. You're using Exception which will catch all exceptions. Instead, only catch exceptions that you know will happen. Find out what exceptions socket might throw.

That way you would have discovered this earlier.

Sign up to request clarification or add additional context in comments.

2 Comments

"mock_sock.return_value = None" that worked and also, changed the positive test to "self.assertRegexpMatches(reference.sock_create(), "closed socket", msg="Failed to call close")" worked.
@amit, what you should be looking to do in the unit test though is match the behaviour that happens in the actual code. In what instance can a socket fail when creating it?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.