2014-02-21 2 views
2

Я пытаюсь проверить функцию, которую я сделал, итерации через список, и вызывает os.path.exists для каждого элемента в списке. Мой тест передает функцию список из двух объектов. Мне нужно os.path.exists, чтобы вернуть True для одного из них и False для другого. Я попытался это:mock/patch os.path.exists с несколькими возвращаемыми значениями

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) 

Использование любой, но не оба линии # 1 и # 2 дают NameError: global name 'side_effect' is not defined

Я нашел этот question и изменил мой код следующим образом:

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) 

И это производит TypeError: 'module' object is not callable. Я также попытался переключения эти строки:

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

для этого

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

и это

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

с той же ошибкой производится. Может ли кто-нибудь указать, что я делаю неправильно, и что я могу сделать, чтобы заставить это работать?

EDIT: После размещения моего ответа ниже, я понял, что мой первый бит коды на самом деле работает хорошо, мне просто нужно m.side_effect = TestClass.side_effect вместо m.side_effect = side_effect.

ответ

3

Итак, после нескольких исследований и испытаний и ошибок, с большинством примеров здесь: http://www.voidspace.org.uk/python/mock/patch.html, я решил свою проблему.

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 вызовы os.path.exist для каждого элемента в arg_list и возвращает список всех элементов, которые os.path.exist вернувшихся True для. Этот тест теперь проходит, как я хочу.

+0

А что, если функция имеет тот же аргумент для обоих вызовов? – hithwen

+0

Что значит? Если 'os.path.exists' передается 1 для обоих вызовов? Затем он вернет True, потому что это то, что говорит побочный эффект. Но он не будет передан один и тот же аргумент дважды, потому что функция 'test' выполняет итерацию через' arg_list' и вызывает 'os.path.exists' для каждого элемента в списке. Поэтому, пока оба элемента в списке не '1', он будет работать так, как ожидалось. –

+0

Я имел в виду, если я хочу дважды вызвать os.path.exists с тем же аргументом и вернуть сначала False, а затем True. Я выяснил, как это сделать, определяя функцию, которая будет подсчитывать, сколько раз было вызвано и возвращало разные значения и использовало ее как side_effect. – hithwen

0

Вы могли бы сделать self.side_effect Я верю. поскольку начальное определение не было глобальным, вызов side_effect просматривает глобальную область

Смежные вопросы