Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

mock xmlrpc.client method python

I am in the process of learning unit testing, however I am struggling to understand how to mock functions for unit testing. I have reviewed many how-to's and examples but the concept is not transferring enough for me to use it on my code. I am hoping getting this to work on a actual code example I have will help.

In this case I am trying to mock isTokenValid.

Here is example code of what I want to mock.

<in library file>

import xmlrpc.client as xmlrpclib   

class Library(object):
    def function:
        #...
        AuthURL = 'https://example.com/xmlrpc/Auth'
        auth_server = xmlrpclib.ServerProxy(AuthURL)
        socket.setdefaulttimeout(20)
        try:
            if pull == 0:
                valid = auth_server.isTokenValid(token)
        #...

in my unit test file I have

import library

class Tester(unittest.TestCase):
    @patch('library.xmlrpclib.ServerProxy')
    def test_xmlrpclib(self, fake_xmlrpclib):
        assert 'something'

How would I mock the code listed in 'function'? Token can be any number as a string and valid would be a int(1)

like image 857
user1601716 Avatar asked Jan 04 '17 05:01

user1601716


People also ask

What is XML-RPC in Python?

XML-RPC is a Remote Procedure Call method that uses XML passed via HTTP as a transport. With it, a client can call methods with parameters on a remote server (the server is named by a URI) and get back structured data.

How do I enable Allow_none on XML-RPC?

In your server class, add allow_none=True to your SimpleXMLRPCServer instantiation. The allow_none and encoding parameters are passed on to xmlrpc. client and control the XML-RPC responses that will be returned from the server.

What is ServerProxy in Python?

A ServerProxy instance is an object that manages communication with a remote XML-RPC server. The required first argument is a URI (Uniform Resource Indicator), and will normally be the URL of the server.

How does XML-RPC work?

In XML-RPC, a client performs an RPC by sending an HTTP request to a server that implements XML-RPC and receives the HTTP response. A call can have multiple parameters and one result. The protocol defines a few data types for the parameters and result. Some of these data types are complex, i.e. nested.


1 Answers

First of all, you can and should mock xmlrpc.client.ServerProxy; your library imports xmlrpc.client as a new name, but it is still the same module object so both xmlrpclib.ServerProxy in your library and xmlrpc.client.ServerProxy lead to the same object.

Next, look at how the object is used, and look for calls, the (..) syntax. Your library uses the server proxy like this:

# a call to create an instance
auth_server = xmlrpclib.ServerProxy(AuthURL)
# on the instance, a call to another method
valid = auth_server.isTokenValid(token)

So there is a chain here, where the mock is called, and the return value is then used to find another attribute that is also called. When mocking, you need to look for that same chain; use the Mock.return_value attribute for this. By default a new mock instance is returned when you call a mock, but you can also set test values.

So to test your code, you'd want to influence what auth_server.isTokenValid(token) returns, and test if your code works correctly. You may also want to assert that the correct URL is passed to the ServerProxy instance.

Create separate tests for different outcomes. Perhaps the token is valid in one case, not valid in another, and you'd want to test both cases:

class Tester(unittest.TestCase):
    @patch('xmlrpc.client.ServerProxy')
    def test_valid_token(self, mock_serverproxy):
        # the ServerProxy(AuthURL) return value
        mock_auth_server = mock_serverproxy.return_value
        # configure a response for a valid token
        mock_auth_server.isTokenValid.return_value = 1

        # now run your library code
        return_value = library.Library().function()

        # and make test assertions
        # about the server proxy
        mock_serverproxy.assert_called_with('some_url')
        # and about the auth_server.isTokenValid call
        mock_auth_server.isTokenValid.assert_called_once()
        # and if the result of the function is expected
        self.assertEqual(return_value, 'expected return value')

    @patch('xmlrpc.client.ServerProxy')
    def test_invalid_token(self, mock_serverproxy):
        # the ServerProxy(AuthURL) return value
        mock_auth_server = mock_serverproxy.return_value
        # configure a response; now testing for an invalid token instead
        mock_auth_server.isTokenValid.return_value = 0

        # now run your library code
        return_value = library.Library().function()

        # and make test assertions
        # about the server proxy
        mock_serverproxy.assert_called_with('some_url')
        # and about the auth_server.isTokenValid call
        mock_auth_server.isTokenValid.assert_called_once()
        # and if the result of the function is expected
        self.assertEqual(return_value, 'expected return value')
like image 198
Martijn Pieters Avatar answered Sep 22 '22 10:09

Martijn Pieters