IAmVerySmart
IAmVerySmart

Reputation: 5

Python mock testing: how can I substitute a function in the test case?

I'm trying to test this kind of method that alters my incoming object, but it needs to be mocked because I can't run the code in a unit test case (requires massive files that aren't in the repo).

I want to mock the function method_to_mock so that it sets the file_wrapper_object.status to whatever I want for that test case.
Note. method_to_mock doesn't return anything.

def method_to_mock(file_wrapper_object):
    try:
        process(file_wrapper_object) #<—- I can't run this in a test case
        file_wrapper_object.status = "COMPLETE"
    except:
        file_wrapper_object.status = "FAILED"

def TestProcessFileWrapperObject(self):
    file_wrapper_object = create_wrapper_object(arbitrary_data)
    method_to_mock(file_wrapper_object)
    self.assertEqual(file_wrapper_object.status, "COMPLETE")

How can I mock a method that doesn't return anything but alters the incoming object?

Upvotes: 0

Views: 96

Answers (1)

User051209
User051209

Reputation: 2538

I have created a file prod.py which contains your production function method_to_mock. To execute the test code I have insert in that file other snippets of code as you can see below:

# this is your production code
def method_to_mock(file_wrapper_object):
    try:
        process(file_wrapper_object) #<—- I can't run this in a test case
        file_wrapper_object.status = "COMPLETE"
    except:
        file_wrapper_object.status = "FAILED"

#+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
# the following code has been created to execute the test code
#+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
class OBJ:
    status = "PARTIAL"

def process(file_wrapper_object):
    print("real function process")

def create_wrapper_object(arbitrary_data):
    return OBJ()

With the previous file the test code (file test_prod.py) is:

import unittest
from unittest.mock import patch
from prod import process, method_to_mock, create_wrapper_object

def func_mock_process(file_wrapper_object):
    print("new function process")

class MyTestCase(unittest.TestCase):

    def test_ProcessFileWrapperObject(self):
        file_wrapper_object = create_wrapper_object('arbitrary_data')
        with patch("prod.process") as mock_process:
            mock_process.side_effect = func_mock_process
            method_to_mock(file_wrapper_object)
            self.assertEqual(file_wrapper_object.status, "COMPLETE")

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

About test code:

  • patch() substitutes the real function process with mock_process
  • mock_process.side_effect = func_mock_process selects the function that must be executed by the production code during the test at the place of process

The output of the test code execution is:

new function process
.
----------------------------------------------------------------------
Ran 1 test in 0.001s
OK

The output shows that:

  • the function process has been substituted by func_mock_process (this is showed by the print message new function process
  • the value of the attribute status is COMPLETE.

Upvotes: 0

Related Questions