The mock method "socket.socket.connect" was called with the specified parameters to approve it while maintaining the functionality

I am using Python 2.7 and mock library to check if a method of an connect

instance of a class object has been called socket.socket

with specific arguments. However, I only want to use the layout as a "marker" and continue to work fine with the function call. In the case below, I want to socket.socket.connect

call the real unplowed function as a "side effect" so the method doesn't break later.

That is, I want the class layout to socket.socket

retain the same functionality and behavior, but with the added ability to record calls.

Here's a (simplified) test. Here's what I think I was wrong:

# test.py
@patch('socket.socket.connect')
@override_settings(SERVER_IP='127.0.0.1')
def test_ip_from_settings(self, connect_mock):
    """
    The IP to connect to is taken from the Django settings.
    """
    def connect(self, address):
        socket.socket.connect(self, address)
    connect_mock.side_effect = connect

    result = connections.get_result()

    connect_mock.assert_called_with(('127.0.0.1', TCP_PORT))

      

And for your reference, this is the (again simplified) code for connecting and getting results:

# connections.py
from django.conf import settings
def get_result():
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    s.connect((settings.SERVER_IP, TCP_PORT))

    query = 'myquery'
    s.sendall(query)
    result = s.recv(BUFFER_SIZE)
    return result

      

However, it TypeError: connect() takes exactly 2 arguments (1 given)

rises when the test is run . How can I do what I want?

+3


source to share


2 answers


To mocking unbound method you have to use autospec=True

to save signature ... But unfortunately socket.socket.connect()

can't be mocked because it is C method . But our goal is not to mock it, but simply to fool it with the layout. So the simplest, but not exactly clean trick I have found is to use a new class to falsify the framework

from mock import ANY

class MyS():
    def connect(self, address): #The signature
        pass

@patch("socket.socket.connect", autospec=MyS.connect, side_effect=socket.socket.connect)
@override_settings(SERVER_IP='127.0.0.1')
def test_ip_from_settings(self, connect_mock):
    """
    The IP to connect to is taken from the Django settings.
    """
    result = connections.get_result()
    connect_mock.assert_called_with(ANY,('127.0.0.1', TCP_PORT))

      

You have to use ANY

from mock helpers because you don't know what socket object will be passed to your shell.

This trick works for either Python3 or Python2.7, but the behavior is slightly different in Python3 because it is socket.socket.connect()

not a function, but method_descriptor

.

>>> import socket
>>> type(socket.socket.connect)
<class 'method_descriptor'>

      



Also in this case the usage autospec=True

doesn't work.


The real question is, are you sure you need a real compound to run your tests. Mock goals are disconnecting testing from real resources, registering calls and asserting arguments is a plus, but the first use is to replace a real object with simple, fast computations and can be configured to return what we need to test certain types of behavior.

Perhaps you really need to patch()

socket.socket

and install some return_values

or side_effect

to test your test in the cases that you check.

+1


source


An inner function connect

within a method test_ip_from_settings

is not a method, but a function. Therefore, you must remove the first argument self

.

It:

def connect(self, address): socket.socket.connect(self, address)

Should be:



def connect(address): socket.socket.connect(address)

This is because of this, when you call s.connect((settings.SERVER_IP, TCP_PORT))

, the tuple (settings.SERVER_IP, TCP_PORT)

is one argument that goes in the argument self

in your case, and then the variable address

still needs to be specified.

In the second correct case, there is no argument self

, so the tuple is bound to the argument address

.

0


source







All Articles