如何在Python中模拟函数以更改默认关键字参数

3 投票
2 回答
1783 浏览
提问于 2025-04-17 14:11

我正在使用mock库和unittest2来测试我的软件项目的不同方面。

现在我有一个问题:有没有办法模拟一个函数,让它的默认关键字参数变得不同,但功能保持不变呢?

假设我有以下代码:

class C():
  def fun(self, bool_arg = True):
    if bool_arg:
      return True
    else
      return False

如果我想模拟C.fun的话:

C.fun = mock.Mock(???)

这样每个C的实例都会把关键字'bool_arg'的值替换成False,而不是True,结果是:

c = C()
c.fun()

返回:

False

2 个回答

2

你可以试试这个代码:

>>> import mock
>>> 
>>> class C():
...   def fun(self, bool_arg = True):
...     if bool_arg:
...       print "True"
...     else:
...       print "False"
... 
>>> c = C()
>>> funCopy = c.fun
>>> c.fun = mock.Mock(side_effect=lambda bool_arg=False: funCopy(bool_arg=bool_arg))
>>> c.fun()
False

希望这对你有帮助

3

你也可以尝试把你的函数包裹起来。可以参考下面的方式:

def wrapper(func, bool_arg):
    def inner(*args, **kwargs):
        kwargs['bool_arg']=bool_arg
        return func(*args, **kwargs)
    return inner

然后

class C():
    def fun(...):
        ...

c = C()
c.fun = wrapper(fun, False)

应该可以正常工作。

编辑

如果你想改变这个类的默认设置,而不是某个特定实例的设置,你可以创建一个派生类,并重新定义 fun,把 C 的方法包裹起来。可以参考下面的方式(我现在没有时间测试):

class D(C):
    def fun(self, *args, **kwargs):
        f = wrapper(C.f, False)
        return f(*args, **kwargs)

关于 @Ber 的建议,你可以定义 def wrapper(func, **wrapkwargs),然后在这里,不用 kwargs['bool_arg']=bool_arg,而是这样做:

for i in wrapkwargs.iteritems():  #wrapkwargs is a dictionary
    kwargs[i[0]] = i[1]

撰写回答