如何模拟两个导入深度的Python类?

2024-10-01 13:40:34 发布

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

如何模拟一个深度为两个导入的Python类,而不更改任何一个导入模块中的代码?假设我正在导入一个web实用程序库,它导入了一个HTTPClient()——我如何编写一个单元测试,模拟HTTPClient返回一个值,而不改变web文件呢_utils.py?我想在DataHandler中使用数据操作(而不是mockitout),但我不希望HTTPClient实际连接到web。在

这有可能吗?考虑到Python有monkey补丁,看起来应该如此。或者有其他/更好的方法吗?我还在弄明白嘲弄的过程,更不用说改变进口了。在

# someLib/web_utils.py
from abc.client import SomeHTTPClient # the class to replace

def get_client():
    tc = SomeHTTPClient(endpoint='url') # fails when I replace the class
    return tc

class DataHandler(object):
    def post_data(someURL, someData):
        newData = massage(someData)
        client = get_client()
        some_response = client.request(someURL, 'POST', newData)
        return some_response

# code/myCode.py
from someLib.web_utils import DataHandler

dh = DataHandler()
reply = dh.post_data(url, data)

# tests/myTests.py
from django.test.testcases import TestCase
from mock import Mock

class Mocking_Test(TestCase):
    def test_mock(self):
        from someLib import web_utils
        fakeClient = Mock()
        fakeClient.request = web_utils.SomeHTTPClient.request # just to see if it works
        web_utils.SomeHTTPClient = fakeClient
        dh = DataHandler()
        reply = dh.post_data(url='somewhere', data='stuff')

Update-添加了get_client()函数。我认为@spicavigo的答案是正确的-它似乎正在替换SomeHTTPClient类。但由于某些原因,类没有实例化对象(错误是,“must be type,not Mock”)。我也不明白它怎么可能是一个已经创建的Mock()对象,而不是一个类。所以我不知道该怎么做。在


Tags: frompyimportclientwebdatadefutils
3条回答

以下是最终奏效的方法:

class Mocking_Test(TestCase):
    def test_mock(self):
        def return_response(a, b, c, *parms, **args):
            print "in request().return_response"
            class makeResponse(object):
                status = 200
                reason = "making stuff up"
            return makeResponse()

        fakeClient = Mock()
        fakeClient.return_value = return_response

        #with patch('abc.client.SomeHTTPClient') as MockClient: # not working.
        with patch('abc.client.SomeHTTPClient.request', new_callable=fakeClient):
            dh = DataHandler()
            reply = dh.post_data(url='somewhere', data='stuff')

在我最初的帖子中,我的思路是正确的,patch,我只是没有正确地进行补丁。另外,我没有替换整个类,而是只替换了类上的request函数(这是所有需要模拟的,以避免实际发出HTTP请求)。在

我知道这并不是您想要的,但是在创建了您的模拟类之后,我会简单地做一些类似的事情,以使代码更干净(在bashshell中,否则如果您有一个文件,您可以只执行查找和替换)

find . -name "*.py" -type f -exec sed -i "s/<old_class>/<mock_class>/g" '{}' \;

这应该会用新类替换旧类的所有实例,我个人认为这会使代码更简洁。如果只需要一个文件,而不是所有.py文件,只需将-name更改为“文件.py““

你能把这个加到我的测试.py试试看

from someLib import web_utils
web_utils.SomeHTTPClient = <YOUR MOCK CLASS>

相关问题 更多 >