【问题标题】:Testing function that interacts with Django Rest Framework API using python mock library使用 python 模拟库与 Django Rest Framework API 交互的测试函数
【发布时间】:2018-09-13 12:08:05
【问题描述】:

我想对一个与使用 Django Rest Framework 构建的 API 交互的模块进行单元测试。为此,我正在使用 python 模拟库。由于我没有使用模拟测试与 API 交互的经验,所以我遇到了问题。

将对象发送到 API 端点的函数是这样的(简而言之):

def send_experiment_to_portal(experiment: Experiment):
    rest = RestApiClient()

    if not rest.active:
        return None

    # general params
    params = {"nes_id": str(experiment.id),
              "title": experiment.title,
              "description": experiment.description,
              "data_acquisition_done":
                  str(experiment.data_acquisition_is_concluded),
              "project_url": experiment.source_code_url,
              "ethics_committee_url": experiment.ethics_committee_project_url
              }

    action_keys = ['experiments', 'create']

    portal_experiment = rest.client.action(
        rest.schema, action_keys, params=params,
    )

return portal_experiment

RestAPIClient 是向 API 进行身份验证的类:

class RestApiClient(object):
    client = None
    schema = None
    active = False

    def __init__(self):
        auth = coreapi.auth.BasicAuthentication(
            username=settings.PORTAL_API['USER'],
            password=settings.PORTAL_API['PASSWORD']
        )
        self.client = coreapi.Client(auth=auth)

        try:
            url = settings.PORTAL_API['URL'] + \
                  (
                      ':' + settings.PORTAL_API['PORT'] if
                      settings.PORTAL_API['PORT'] else ''
                  ) \
                  + '/api/schema/'

            self.schema = self.client.get(url)
            self.active = True
        except:
            self.active = False

RestApiClient 类正在使用coreapi 客户端模块连接到 API。

所以,最后,我开始测试rest.client.action 中的params 参数是否具有API 使用python 模拟库预见的键/值。

我开始编写初始测试,例如:

class PortalAPITest(TestCase):

    @patch('experiment.portal.RestApiClient')
    def test_send_experiment_to_portal(self, mockRestApiClientClass):
        research_project = ObjectsFactory.create_research_project()
        experiment = ObjectsFactory.create_experiment(research_project)

        result = send_experiment_to_portal(experiment)

所以当我调试测试时,查看send_experiment_to_portal 函数rest.client.action.call_args 的值:

call(<MagicMock name='RestApiClient().schema' id='139922756141240'>, ['expreiments', 'create'], params={'description': 'Descricao do Experimento-Update', 'ethics_committee_url': None, 'project_url': None, 'title': 'Experimento-Update', 'nes_id': '37', 'data_acquisition_done': 'False'})

但是mockRestApiClientClass.client.action.call_argsNone。我怀疑我做错了。我应该模拟 rest.client.action 而不是 RestApiClient 类。

尝试使用result 值也不起作用。

结果的值为

<MagicMock name='RestApiClient().client.action()' id='139821809672144'>

result.call_args 也是None

但是怎么做呢?如何在send_experiment_to_portal函数之外获取模拟rest实例?

【问题讨论】:

    标签: python django unit-testing mocking


    【解决方案1】:

    苦苦挣扎了几天,终于找到了解决办法。

    Mocking RestApiClient 返回类的模拟而不是它的值,即rest 变量的值。我们从模拟对象中调用return_value 得到rest 值。

    所以,我们必须调用mockRestApiClientClass.return_value 而不是mockRestApiClientClass

    通过这样做,我们可以访问从send_experiment_end_message_to_portal 内部调用的rest 方法和属性,然后 mockRestApiClientClass.return_value.client.action.call_args 将具有与 send_experiment_end_message_to_portal 函数上下文中观察到的 rest 内容相同的内容。

    【讨论】:

      猜你喜欢
      • 2018-07-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多