Patch - Patching the class introduces an extra parameter?

golmschenk picture golmschenk · Apr 17, 2013 · Viewed 8.6k times · Source

First time using patch. I've tried to patch one of my classes for testing. Without the patch attempting to run gets past the test function definition, but with the patch the test function definition apparently requires another parameter and I get a

TypeError: testAddChannelWithNamePutsChannel() takes exactly 1 argument (2 given)

Error. The test code is the following:

import unittest
import mock
from notification.models import Channel, addChannelWithName, deleteChannelWithName

class TestChannel(unittest.TestCase):
    @mock.patch('notification.models.Channel')
    def testAddChannelWithNamePutsChannel(self):
        addChannelWithName('channel1')
        Channel.put.assert_called_with()

Why does it require an extra parameter with the patch and what should this parameter be? Thank you much!

Answer

aychedee picture aychedee · Apr 17, 2013

Patch passes in an instance of the patched object to your test method (or to every test method if you are patching at the class level). This is handy because it lets you set return values and side effects, or check the calls made

from unittest.mock import patch

@patch('some_module.sys.stdout')
def test_something_with_a_patch(self, mock_sys_stdout):
    mock_sys_stdout.return_value = 'My return value from stdout'

    my_function_under_test()

    self.assertTrue(mock_sys_stdout.called)
    self.assertEqual(output, mock_sys_stdout.return_value)

If you just want to literally patch something out to ignore it then you can call patch with the following invocation

from unittest.mock import patch, Mock

@patch('some_module.sys.stdout', Mock())
def test_something_with_a_patch(self):

That replaces sys.stdout in the some_module with a Mock object and does not pass it to the method.