Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

mock/patch os.path.exists with multiple return values

I'm trying to test a function that I made that iterates through a list, and calls os.path.exists for each item in the list. My test is passing the function a list of 2 objects. I need os.path.exists to return True for one of them and False for the other. I have tried this:

import mock
import os
import unittest

class TestClass(unittest.TestCase):
    values = {1 : True, 2 : False}
    def side_effect(arg):
        return values[arg]

    def testFunction(self):
        with mock.patch('os.path.exists') as m:
            m.return_value = side_effect # 1
            m.side_effect = side_effect # 2

            arglist = [1, 2]
            ret = test(argList)

Using either but not both of line #1 and #2 give NameError: global name 'side_effect' is not defined

I found this question and modified my code like so:

import mock
import os

class TestClass(unittest.TestCase):
    values = {1 : True, 2 : False}
    def side_effect(arg):
        return values[arg]

    def testFunction(self):
        mockobj = mock(spec=os.path.exists)
        mockobj.side_effect = side_effect

        arglist = [1, 2]
        ret = test(argList)

And this produces TypeError: 'module' object is not callable. I also tried switching these lines:

mockobj = mock(spec=os.path.exists)
mockobj.side_effect = side_effect

for this

mockobj = mock(spec=os.path)
mockobj.exists.side_effect = side_effect

and this

mockobj = mock(spec=os)
mockobj.path.exists.side_effect = side_effect

with the same error being produced. Can anyone point out what it is that I am doing wrong and what I can do to get this to work?

EDIT: After posting my answer below I realised that my first bit of code actually works as well, I just needed m.side_effect = TestClass.side_effect instead of m.side_effect = side_effect.

like image 659
Yep_It's_Me Avatar asked Feb 21 '14 06:02

Yep_It's_Me


1 Answers

So after a bit more research and trial and error, with most of the examples here: http://www.voidspace.org.uk/python/mock/patch.html, I solved my problem.

import mock
import os

def side_effect(arg):
    if arg == 1:
        return True
    else:
        return False

class TestClass(unittest.TestCase):
    patcher = mock.patch('os.path.exists')
    mock_thing = patcher.start()
    mock_thing.side_effect = side_effect
    arg_list = [1, 2]
    ret = test(arg_list)
    self.assertItemsEqual([1], ret)

test calls os.path.exist for each item in arg_list, and returns a list of all items that os.path.exist returned True for. This test now passes how I want it.

like image 122
Yep_It's_Me Avatar answered Sep 23 '22 23:09

Yep_It's_Me