模拟接受**kwargs的函数

2024-09-28 05:28:22 发布

您现在位置:Python中文网/ 问答频道 /正文

我无法模拟接受**kwargs的函数。在这种情况下,我有一个ClassA(在我的具体例子中是我没有编写的),它有一个带有**kwargs的函数。类B,它有一个类A的实例,并调用**kwargs函数。我想通过模拟对类A函数的调用来测试类B。在

以下是我迄今为止所做的尝试,在我的两次尝试中,我都以输入错误而告终。有办法吗?我应该重新考虑一下这个问题的另一个方面吗?在

import unittest


#a class i have no control over. Has a function accepting **kwargs
class ClassA(object):

    def classFunctionAcceptingKwargs(self, **kwargs):
        return kwargs["a"] + kwargs["b"]

# a mock of the above class
class Mock_ClassA(object):

    def __init__(self):
        self.mockclassFunctionAcceptingKwargs = lambda **kwargs: None

    def classFunctionAcceptingKwargs(self, **kwargs):
        #FAILS: TypeError: mockFunctionAcceptingKwargs() takes exactly 0 arguments (1 given)
        return self.mockclassFunctionAcceptingKwargs(kwargs)
        #ALSO FAILS: TypeError: mockFunctionAcceptingKwargs() argument after ** must be a mapping, not set
        #return self.mockclassFunctionAcceptingKwargs(**{kwargs["a"] + kwargs["b"]})

#class B calls the class A kwargs but exposes a function with a dict
class ClassB(object):
    def __init__(self, classA):
        self.classA = classA

    def doSomething(self, dict):
        return self.classA.classFunctionAcceptingKwargs(**dict)

class TestClassA(unittest.TestCase):

    def runTest(self):
        a = ClassA()
        result = a.classFunctionAcceptingKwargs(**{"a":1, "b": 2})
        self.assertEqual(result, 3)

class TestClassB(unittest.TestCase):

    def runTest(self):

        mock = Mock_ClassA()
        def mockFunctionAcceptingKwargs(**kwargs):
            self.assertEqual(kwargs["a"], 1)
            self.assertEqual(kwargs["b"], 2)

        mock.mockclassFunctionAcceptingKwargs = mockFunctionAcceptingKwargs
        b = ClassB(mock)
        b.doSomething({"a": 1, "b": 2})

堆栈跟踪:

^{pr2}$

Tags: 函数selfreturnobjectdefunittestmockdict
1条回答
网友
1楼 · 发布于 2024-09-28 05:28:22

我不知道你为什么要调用另一个函数。但是如果必须有一个实例属性mockclassFunctionAcceptingKwargs函数,那么只需使用**kwargs传递kwargs字典:

class Mock_ClassA(object):
    # ...
    def classFunctionAcceptingKwargs(self, **kwargs):
        return self.mockclassFunctionAcceptingKwargs(**kwargs)

如果您只需要classFunctionAcceptingKwargs存在,则根本不需要调用该lambda:

^{pr2}$

然后只需传入模拟的返回值,无论您需要为测试传递回ClassB,然后您可以检查是否传入了正确的值:

mock = Mock_ClassA(3)  # to return 3 back to the caller
b = ClassB(mock)
b.doSomething({"a": 1, "b": 2})
self.assertEqual(mock.called_with, {'a': 1, 'b': 2})

您可能希望使用^{} library来构建一个要传入的模拟对象(在python3中可用,并且可以为python2安装一个backport)。它将允许您创建一个模拟的ClassA,然后使用API测试mock是否以预期的方式使用:

try:
    # Python 3
    from unittest import mock
except ImportError:
    # Python 2, backport
    import mock

class TestClassB(unittest.TestCase):
    def runTest(self):
        mockA = mock.Mock(spec=ClassA)  # only accept attributes ClassA also has
        mockA.classFunctionAcceptingKwargs.return_value = 3  # or whatever else you want it to return
        b = ClassB(mockA)
        b.doSomething({"a": 1, "b": 2})
        mockA.classFunctionAcceptingKwargs.assert_called_once_with(a=1, b=2)

演示使用unittest.mock作为模拟层:

>>> from unittest import mock
>>> class ClassA(object):
...     def classFunctionAcceptingKwargs(self, **kwargs):
...         return kwargs["a"] + kwargs["b"]
...
>>> class ClassB(object):
...     def __init__(self, classA):
...         self.classA = classA
...     def doSomething(self, dict):
...         return self.classA.classFunctionAcceptingKwargs(**dict)
...
>>> mockA = mock.Mock(spec=ClassA)
>>> mockA.classFunctionAcceptingKwargs.return_value = 3
>>> b = ClassB(mockA)
>>> b.doSomething({"a": 1, "b": 2})
3
>>> mockA.classFunctionAcceptingKwargs.assert_called_once_with(a=1, b=2)  # passes, no exception raised
>>> mockA.mock_calls
[call.classFunctionAcceptingKwargs(a=1, b=2)]

相关问题 更多 >

    热门问题