TravisVOX
TravisVOX

Reputation: 21631

How do you test a function that contains a mocked object instantiated in said function?

I'm still green when it comes to testing/mocking and I've been struggling with this today.

In file.py...

class FileImporter:
    
    def __init__(self, file=None):
        self.file = file
        
    def process_file(self):
        # process file here...


def import_file(file):
    f = FileImporter(file)
    f.process_file()
    return file

Then in test.py...

import mock
import pytest

from file import import_file

@mock.patch('file.FileImporter')
def test_import_file(m_importer):
    
    result = import_file('test.csv')
    m_importer.assert_called_with('test.csv')
    m_importer.process_file.assert_called_once()
    

The test above passes the m_importer.assert_called_with('test.csv') but fails on m_importer.process_file.assert_called_once(). How do I properly handle this? Or is this the wrong way to approach this all together? Thank you!

Upvotes: 0

Views: 40

Answers (1)

gold_cy
gold_cy

Reputation: 14216

So you almost have the correct answer, the issue is that when you instantiate a Mock object it returns a new object.

return_value: The value returned when the mock is called. By default this is a new Mock (created on first access). See the return_value attribute.

That means when the following line is called it returns a new Mock object.

f = FileImporter(file)

The test however is testing the original Mock object. To get around this we can set the return_value of the Mock object to be itself that way we can test the original patched object.

@mock.patch('file.FileImporter')
def test_import_file(m_importer):
    # when instantiated the Mock object will return itself as opposed to a new
    # instance of a Mock
    m_importer.return_value = m_importer
    
    result = import_file('test.csv')
    m_importer.assert_called_with('test.csv')
    m_importer.process_file.assert_called_once()

Upvotes: 1

Related Questions