【问题标题】:Python Mox: How to fake os.path.exists() for certain paths only?Python Mox:如何仅针对某些路径伪造 os.path.exists()?
【发布时间】:2015-02-22 16:36:56
【问题描述】:

我怎样才能只为某些路径模拟exists(),同时让它为任何其他路径做真实的事情?

例如,被测类将调用exists(),并且在提供给它的路径上会失败,因为它们在运行测试的系统上不存在。

使用 Mox 可以完全删除 exists(),但这会使测试失败,因为与被测类无关的调用不会以真实方式起作用。

我想当exists() 被调用时我可以使用WithSideEffects() 来调用我自己的函数,将调用分支到两个方向,但是我怎样才能访问原始的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()

【问题讨论】:

    标签: python mocking partial stub mox


    【解决方案1】:

    Mox 在内部使用“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))
    

    由于中间调用的返回值缓存在被模拟的方法对象中,它必须在副作用回调中重置。

    当一个方法模拟被创建时,它将被推送到将存储在_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()
    

    【讨论】:

      猜你喜欢
      • 2012-07-06
      • 2019-03-18
      • 2012-12-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-01-03
      • 1970-01-01
      • 2019-03-12
      相关资源
      最近更新 更多