【问题标题】:How to mock a Python class to change just one argument如何模拟 Python 类以仅更改一个参数
【发布时间】:2019-06-05 04:02:01
【问题描述】:

我需要像这样将一个类包装在一个模拟中:

原码:

class _InnerImpl(object):

  def __init__(self, arg1, arg2, arg3):
    # do stuff

我想做这样的事情:

from unittest.mock import patch

def my_wrapper(*args, **kwargs):
  kwargs['arg1'] = gen_next_value()  # change one of the arguments
  return _InnerImpl(*args, **kwargs)  # call the real thing with modified args

def run(user_input):
  with patch(_InnerImpl, my_wrapper):
     some_method(user_input)

不幸的是patch 的工作方式,我不能称之为“真实的东西”,因为它也在with patch 块内被调用。这会导致无限递归循环。

我在单元测试之外的实现中使用它。所以这不适用于单元测试。我尝试了各种方法,例如保存__init__ 参考,使用wraps。没有任何效果。

【问题讨论】:

    标签: python mocking python-mock


    【解决方案1】:

    我建议不要对不是单元测试的东西使用模拟。如果我理解您的示例,您似乎需要的是工厂方法模式https://en.wikipedia.org/wiki/Factory_method_pattern

    如果您无法修改正在修补的代码,请尝试使用不同的命名空间。例如,给定目标代码a.py

    class A(object):
        def __init__(self, v):
            print('A({})'.format(v))
    
    def foo():
        y = A('a')
    

    你可以写b.py

    from unittest.mock import patch
    from a import A,foo
    def my_wrapper(*args, **kwargs):
        return A('b')
    def bar():
        with patch('a.A', my_wrapper):
            foo()
    

    【讨论】:

    • 在这种情况下,我不拥有底层代码,也不能更改面向用户的界面。所以我唯一的选择就是在中间拦截电话。
    • 可能答案是利用这里的信息:docs.python.org/3.5/library/unittest.mock.html#where-to-patch 并在修补命名空间a 之前导入另一个命名空间b。那么b 命名空间版本仍​​然会指向原来的。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-08
    • 2021-04-25
    • 1970-01-01
    • 2020-08-08
    • 1970-01-01
    • 2021-10-25
    相关资源
    最近更新 更多