Home > Net >  Can't mock a module method when importing by name
Can't mock a module method when importing by name

Time:07-09

I don't understand why I can't do this operation when trying to mock time.sleep() -- the sleep() method will still delay the given time:

import unittest
from unittest.mock import patch

from time import sleep

class TestTime(unittest.TestCase):

    @patch('time.sleep', return_value=None)
    def test_time(self, mock_time):
        sleep(10) # still delays 10s

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

This works properly:

import unittest
from unittest.mock import patch

import time

class TestTime(unittest.TestCase):

    @patch('time.sleep', return_value=None)
    def test_time(self, mock_time):
        time.sleep(10) # instant

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

This results in an error TypeError: Need a valid target to patch. You supplied: 'sleep':

import unittest
from unittest.mock import patch

from time import sleep

class TestTime(unittest.TestCase):

    @patch('sleep', return_value=None) # error
    def test_time(self, mock_time):
        sleep(10)

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

Is there a proper way to mock sleep() without needing to change all the modules I'm trying to test to use time.sleep()?

My setup:

  • Python version: 3.8.12
  • OS: Windows 10 21H1 (19043.1766)

CodePudding user response:

The reason importing sleep by name doesn't allow patch to work in the examples is that patch is looking for attribute names on an object in order to patch it. When importing by name, the object isn't provided and thus why there is a TypeError. The sleep method is now in the namespace of the module importing it, so you can use that to properly patch sleep.

To import sleep by name and properly patch it, the following will work:

import unittest
from unittest.mock import patch

from time import sleep

class TestTime(unittest.TestCase):

    @patch('__main__.sleep', return_value=None)
    def test_time(self, mock_time):
        sleep(10)

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

As a caveat, if you have a module named my_module that uses from time import sleep and a separate file for tests, you can do the following within the test file to patch sleep within my_module:

@patch('my_module.sleep', return_value=None)

  • Related