Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to mock imported library methods with unittest.mock in Python 3.5?

Is it possible to mock methods of imported modules with unittest.mock in Python 3.5?

# file my_function.py
import os
my_function():
    # do something with os, e.g call os.listdir
    return os.listdir(os.getcwd())

# file test_my_function.py
test_my_function():
    os = MagickMock()
    os.listdir = MagickMock(side_effect=["a", "b"])
    self.assertEqual("a", my_function())

I expected that the the os.listdir method returns the specified side_effect "a" on the first call, but inside of my_function the unpatched os.listdir is called.

like image 236
Kevin Streicher Avatar asked Oct 19 '22 19:10

Kevin Streicher


1 Answers

unittest.mock have two main duties:

  • Define Mock objects: object designed to follow your screenplay and record every access to your mocked object
  • patching references and recover the original state

In your example, you need both functionalities: Patching os.listdir reference used in production code by a mock where you can have complete control of how it will respond. There are a lot of ways to use patch, some details to take care on how use it and cavelets to know.

In your case you need to test my_function() behaviour and you need to patch both os.listdir() and os.getcwd(). Moreover what you need is control the return_value (take a look to the pointed documentation for return_value and side_effect differences).

I rewrote your example a little bit to make it more complete and clear:

my_function(nr=0):
    l = os.listdir(os.getcwd())
    l.sort()
    return l[nr]

@patch("os.getcwd")
@patch("os.listdir", return_value=["a","b"])
def test_my_function(mock_ld, mock_g): 
    self.assertEqual("a", my_function(0))
    mock_ld.assert_called_with(mock_g.return_value)
    self.assertEqual("a", my_function())
    self.assertEqual("b", my_function(1))
    with self.assertRaises(IndexError):
        my_function(3)

I used the decorator syntax because I consider it the cleaner way to do it; moreover, to avoid the introduction of too many details I didn't use autospecing that I consider a very best practice.

Last note: mocking is a powerful tool but use it and not abuse of it, patch just you need to patch and nothing more.

like image 185
Michele d'Amico Avatar answered Oct 21 '22 15:10

Michele d'Amico