Andriy Ivaneyko
Andriy Ivaneyko

Reputation: 22041

How to apply @mock.patch for method and keep access to original method within one or more Tests?

While working on unittests for python application I faced interesting case when mock.patch activate mocking via start() method. To reproduce problem put code below into two files tests.py and utils.py and place them under one folder:

tests.py:

import mock
import unittest

import utils


class TestA(unittest.TestCase):

    def setUp(self):
        pass

    def test_method_a(self):
        mock.patch('utils.method_b', return_value=None).start()
        actual_result = utils.method_a()
        # Assertion code

    def test_method_b(self):
        actual_result = utils.method_b()
        self.assertTrue(actual_result is None)

utils.py:

def method_a():
    print 'A Method'
    return method_b()

def method_b():
    print 'B Method'
    return True

Pay attention that test_method_a mocking app_utils.method_b and test_method_b are going to call original app_utils.method_b. I faced situation that test_method_b cannot call actual app_utils.method_b because it's mocked by test_method_a.

I knew few methods of how to resolve that problem:

The question is whether that possible to resolve problem without applying solutions above?

I need to keep using mock.patch and imports as is, if possible.

Upvotes: 1

Views: 1810

Answers (1)

Andriy Ivaneyko
Andriy Ivaneyko

Reputation: 22041

The weird behaviour described above occurred due to not stopping of patcher which mock method_b.

See working code below:

utils.py file is the same as in question.

tests.py:

import mock
import unittest

import utils


class TestA(unittest.TestCase):

    def setUp(self):
        pass

    def test_method_a(self):
        method_b_patcher = mock.patch('utils.method_b', return_value=None)
        method_b_patcher.start()
        actual_result = utils.method_a()
        method_b_patcher.stop()

    def test_method_b(self):
        actual_result = utils.method_b()
        self.assertTrue(actual_result)

So what is updated is that in test_method_a i've added method_b_patcher and call start and stop for that patcher within test_method_a method.

Upvotes: 1

Related Questions