0

I'm want to mock or stub a function for testing. Not sure if I have the terminology right so correct me if I'm wrong, but I understand a mock as using a mocking library similar to unittest.mock to create a fake object and has expectations about what parameters it will receive and what what it will return, etc. This seems a bit of overkill to me since all I want is the mocked/stubbed method to do is return a set value.

I think of stubbing as just 'mocking without a library', like the answer to this question. From what I can see, this is exactly what I want. It's light and simple and you don't have to mess around with all the options of mocking for the simple cases.

My question is, is it safe to do this? The question above seems to be overwriting the in memory representation of a method, and it just doesn't seem right. Is this accepted by the python community? Or is it encouraged to use a proper mocking library all the time?

EDIT What kind of horrible things would happen if you didn't reassign the method in the finally block, as the linked answer states?

Community
  • 1
  • 1
Yep_It's_Me
  • 4,494
  • 4
  • 43
  • 66
  • To check to see if your test is safe, write another test to test your mocking. Nothing like metatesting! – acutesoftware Aug 01 '14 at 06:14
  • Actually, what you describe (an object returning a set value) is exactly what the built-in mock library does, as you can see from the doc page you link to. – Daniel Roseman Aug 01 '14 at 06:21
  • 3
    the main commonly accepted difference between a mock and a stub is that a stub returns data the test needs to pass and can never cause a test to fail. A mock is used to verify expectations on interactions between different components. Both mocking and stubbing can be done with out a library. – Sam Holder Aug 01 '14 at 07:51

1 Answers1

4

The main reason I wanted to stub the method myself was so that I wouldn't have to worry about a mock and go through setting it up. However I found this blog post which shows an excellent way to use the mock library with annotations making it a lot easier than creating an instance of Mock manually. Here is an excerpt:

rm.py

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import os
import os.path

def rm(filename):
    if os.path.isfile(filename):
        os.remove(filename)

rmtest.py

#!/usr/bin/env python
# -*- coding: utf-8 -*-

from mymodule import rm

import mock
import unittest

class RmTestCase(unittest.TestCase):

    @mock.patch('mymodule.os.path')
    @mock.patch('mymodule.os')
    def test_rm(self, mock_os, mock_path):
        # set up the mock
        mock_path.isfile.return_value = False

        rm("any path")

        # test that the remove call was NOT called.
        self.assertFalse(mock_os.remove.called, "Failed to not remove the file if not present.")

        # make the file 'exist'
        mock_path.isfile.return_value = True

        rm("any path")

        mock_os.remove.assert_called_with("any path")
Yep_It's_Me
  • 4,494
  • 4
  • 43
  • 66