如何在嵌套类中模拟实例变量

时间:2014-12-18 21:38:53

标签: python unit-testing mocking instagram

简化示例:

def bind_method(**config):
    class InstagramAPIMethod(object):
        def __init__(self, *args, **kwargs):
            self.return_json = kwargs.pop("return_json", False)
    def _call(*args, **kwargs):
        method = InstagramAPIMethod(*args, **kwargs)
        return method.__dict__

    return _call

class InstAPI():
  result = bind_method(foo='bar')

api = InstAPI()
print api.result()

# {'return_json': False}

从上面的例子中有没有办法“猴子补丁”“InstAPI”实例或使用“部分”函数将值硬编码为“_call”函数,以便它返回{'return_json': True}

Reallife示例:

https://github.com/Instagram/python-instagram.git

如果你看https://github.com/Instagram/python-instagram/blob/master/instagram/bind.py#L42-L69

您将看到bind_method函数,如下所示:

def bind_method(**config):
  class InstagramAPIMethod(object):
    path = config['path']
    method = config.get('method', 'GET')

https://github.com/Instagram/python-instagram/blob/master/instagram/bind.py#L64行中有一个参数。我找不到如何将其更改为True的明确方法。

1 个答案:

答案 0 :(得分:1)

mock给你一些方法来做。这个案子有点棘手,因为

  1. InstagramAPIMethodbind_method function
  2. 中定义
  3. InstAPI在加载时存储bind_method定义
  4. 因此补丁bind_methodInstagramAPIMethod类无效。你只有一次机会:补丁InstAPI.result。我考虑了2个案例:

    1. 我不关心bind_method中的工作,我只需api.result()返回{'return_json': True}
    2. 这样的词典
    3. 我希望result()完全返回bind_method返回的内容,除了更改某些值
    4. 遵循玩具示例的代码,该代码也应该在现实生活中起作用。

      def bind_method(**config):
          class InstagramAPIMethod(object):
              def __init__(self, *args, **kwargs):
                  self.return_json = kwargs.pop("return_json", False)
          def _call(*args, **kwargs):
              method = InstagramAPIMethod(*args, **kwargs)
              return method.__dict__
          return _call
      
      class InstAPI():
        result = bind_method(foo='bar')
      
      api = InstAPI()
      print api.result()
      
      
      from mock import patch
      #Patch directly InstAPI.result
      with patch("__main__.InstAPI.result",return_value={'return_json': True}):
          api = InstAPI()
          print api.result()
      
      #The wrapper of bind_method
      def new_instapi_result(**kwargs):
          def functor(**config):
              d = bind_method(**config)()
              d.update(kwargs)
              return d
          return functor
      
      #Patch and wrap bind_method
      with patch("__main__.InstAPI.result",side_effect=new_instapi_result(return_json = True)):
          api = InstAPI()
          print api.result()