Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to import own module for mocking? (import error: no module named my_module!)

I want to unit test my class, which is in another file named client_blogger.py.

My unit test file, is in the same directory. All of my other unit tests work, except when I try to mock one of my own methods.

## unit_test_client_blogger.py
import mock
import json

from client_blogger import BloggerClient, requests

Class TestProperties():

    @pytest.fixture

    def blog(self):
    return BloggerClient(api_key='123', url='http://example.com')

    @mock.patch('client_blogger._jload')
    @mock.patch('client_blogger._send_request')

    def test_gets_blog_info(self, mock_send, mock_jload):
    """ Get valid blog info from API response. """

    valid_blog_info = 'some valid json api response here'
    parsed_response = json.loads(valid_blog_info)
    correct_blog_id = '7488272653173849119'
    mock_jload.return_value = valid_blog_info

    id = self.blog().get_blog_info(parsed_response)
    assert id == correct_blog_id

And here is the client_blogger.py file contents:

# client_blogger.py
import requests, json

class BloggerClient(object):
    """ Client interface for Blogger API. """
    def __init__(self, key, url):
         # removed some code here for brevity

    def _send_request(self, api_request):
        """ Sends an HTTP get request to Blogger API.
            Returns HTTP response in text format. """
        # snip

    def _jload(self, api_response):
        """ Accepts text API response. Returns JSON encoded response. """
        # snip

    def get_blog_info(self):
        """ Makes an API request. Returns Blog item information. """
        request = '{b}/blogs/byurl?url={u}&key={k}'.format(b=self.base, u=self.url, k=self.key)
        txt_response = self.send_request(request)
        response = self._jload(txt_response)
        return response['id']

I want to mock out self.send_request() and self._jload() method calls in the above method.

But Mock module complains: ImportError: No module named client_blogger.

The error must lie here:

@mock.patch('client_blogger._jload')
@mock.patch('client_blogger._send_request')

I've tried many variations in order to get mock.patch to find my module or class. But none of them have worked.

I've tried the following:

@mock.patch('client_blogger.BloggerClient._jload')
@mock.patch('BloggerClient._jload')
@mock.patch('._jload')

None of those work. Any idea how to mock.patch a method from my own module?

(It seems strange, because I can mock.patch other modules, just not my own :-s)

like image 574
BBedit Avatar asked Sep 12 '14 14:09

BBedit


People also ask

Can you mock an import in Python?

Rather than hacking on top of Python's import machinery, you can simply add the mocked module into sys. path , and have Python prefer it over the original module. Now, when the test suite is run, the mocked-lib subdirectory is prepended into sys. path and import A uses B from mocked-lib .

What is mock Pytest?

New in version 3.3. unittest.mock is a library for testing in Python. It allows you to replace parts of your system under test with mock objects and make assertions about how they have been used.


1 Answers

You want this:

@mock.patch('client_blogger.BloggerClient._jload')
@mock.patch('client_blogger.BloggerClient._send_request')
def test_gets_blog_info(self, mock_send, mock_jload):
    """ Get valid blog info from API response. """

    valid_blog_info = 'some valid json api response here'
    parsed_response = json.loads(valid_blog_info)
    correct_blog_id = '7488272653173849119'
    mock_jload.return_value = valid_blog_info

    id = self.blog().get_blog_info(parsed_response)
    assert id == correct_blog_id

The BloggerClient implementation is coming from the client_blogger module, so you need to patch client_blogger.BloggerClient. You list that as one of the things you tried that doesn't work, but I just tried it, and it works fine for me. What issue did you have when you tried that?

like image 162
dano Avatar answered Oct 08 '22 18:10

dano