2015-02-22 5 views
0

Как я могу высмеять exists() для определенных путей только при том, что это делает реальную вещь для любого другого пути?Python Mox: Как подделать os.path.exists() только для определенных путей?

Например, тестируемый класс вызовет exists() и завершит сбой на путях, которые были ему предоставлены, поскольку они не существуют в системе, где выполняются тесты.

С Mox можно полностью отключить exists(), но это приведет к сбою теста, потому что вызовы, не связанные с тестируемым классом, не будут действовать в реальном режиме.

Я думаю, я мог бы использовать WithSideEffects(), чтобы вызвать свою собственную функцию, когда exists() называется разветвлением вызова в двух направлениях, но как я могу получить доступ к оригиналу exists()?

Это то, что я до сих пор:

def test_with_os_path_exists_partially_mocked(self): 

    self.mox.StubOutWithMock(os.path, 'exists') 

    def exists(path): 
     if not re.match("^/test-path.*$", path): 
      return call_original_exists_somehow(path) 
     else: 
      # /test-path should always exist 
      return True 

    os.path.exists(mox.Regex("^.*$")).MultipleTimes().WithSideEffects(exists) 

    self.mox.ReplayAll() 

    under_test.run() 

    self.mox.VerifyAll() 

ответ

0

СОТ внутренне использует "Stubout" для фактического гася:

Mox.__init__() 
    self._mock_objects = [] 
    self.stubs = stubout.StubOutForTesting() 


Mox.StubOutWithMock() 
    ... 
    self.stubs.Set(obj, attr_name, stub) 

Stubout сохраняет заглушки во внутренней коллекции:

StubOutForTesting.Set(): 
    ... 
    self.cache.append((parent, old_child, child_name)) 

Поскольку возвращаемое значение промежуточных вызовов кэшируется в объект издеваемого метода, его необходимо сбросить в обратный вызов побочного эффекта.

При создании метода mock он будет перенесен в файл _expected_calls_queue. В режиме воспроизведения ожидаемый вызов отображается экземпляром MultipleTimesGroup, который будет отслеживать вызовы по каждому методу, указанному в _methods.

Итак, можно обратиться к оригинальному методу, проводя Mox.stubs.cache.

В этом примере будет высмеиваться exists(), проходящий через вызовы к исходной функции, если они не начинаются с /test-path, любой другой вызов всегда будет возвращаться True.

class SomeTest(unittest.TestCase): 

    def setUp(self): 
     self.mox = mox.Mox() 

    def tearDown(self): 
     self.mox.UnsetStubs() 

    def test_with_os_path_exists_partially_mocked(self): 

     self.mox.StubOutWithMock(os.path, 'exists') 

     # local reference to Mox 
     mox_ = self.mox 

     # fake callback 
     def exists(path): 
      # reset returnvalues of previous calls 
      # iterate mocked methods. the indices denote 
      # the mocked object and method and should 
      # have the correct values 
      for method in mox_._mock_objects[0]._expected_calls_queue[0]._methods: 
       method._return_value = None 

      if not re.match("^/test-path.*$", path): 
       # call real exists() for all paths not 
       # starting with /test-path 

       # lookup original method: 
       # - filter by name only (simplest matching) 
       # - take the 2nd value in the tupel (the function) 
       orig_exists = filter(lambda x: x[2] == "exists", mox_.stubs.cache)[0][1] 
       # call it 
       return orig_exists(path) 
      else: 
       # hardcoded True for paths starting with /test-path 
       return True 

     # expect call with any argument, multiple times, and call above fake 
     os.path.exists(mox.Regex("^.*$")).MultipleTimes().WithSideEffects(exists) 

     self.mox.ReplayAll() 

     # test goes here 

     self.mox.VerifyAll()