【问题标题】:Python unittest mock an API keyPython unittest 模拟 API 密钥
【发布时间】:2015-05-07 20:10:56
【问题描述】:

我正在为 client.py 的 Client 类编写单元测试,它查询 API。每个测试都使用c = client.Client("apikey") 实例化客户端。一次运行一个测试可以正常工作,但运行所有测试(例如使用py.test)我得到一个 401:“异常:响应 401:未经授权的访问。请求必须包含有效的 api-key。”

我有一个有效的 API 密钥,但这不应该包含在单元测试中。我会很感激解释为什么"apikey" 只适用于一个查询。更具体地说,如何模拟对 API 的调用?下面是一个示例单元测试:

def testGetContextReturnFields(self):
  c = client.Client("apikey")
  contexts = c.getContext("foo")

  assert(isinstance(contexts[0]["context_label"], str))
  assert(contexts[0]["context_id"] == 0)

【问题讨论】:

  • 模拟什么以及如何模拟在很大程度上取决于Client 类的内部结构。毕竟,您可以只是模拟 Client.getContext 以返回固定的东西,但是您只是在测试您配置模拟以匹配预期的输出。
  • 我不确定我是否理解正确:你想通过真正调用 API 来测试 Client 吗?您应该信任 API(您不能再次测试 API)并且只测试您的客户端是否进行了正确的调用。
  • @Micheled'Amico 如何在不实际查询 API 的情况下测试我的客户端对 API 的正确查询?
  • 不知道 API 是什么就很难回答。在某些情况下,您可以编写自己的直接接口(1-1 到 API 调用),您可以在测试环境中替换为假的或模拟 http 请求(如果它是 http API)。在 python 中,直接模拟库很简单,无需创建自己的接口:这种方式是 C、C++ 和 Java 中的最佳实践。看看mock framework

标签: python mocking api-key python-unittest


【解决方案1】:

将 API 调用和 Client.getContext() 方法的测试分开。要显式测试 API 调用,请修补请求对象...

import client
import httpretty
import requests
from mock import Mock, patch
...
def testGetQueryToAPI(self):
  """
  Tests the client can send a 'GET' query to the API, asserting we receive
  an HTTP status code reflecting successful operation.
  """
  # Arrange: patch the request in client.Client._queryAPI().
  with patch.object(requests, 'get') as mock_get:
    mock_get.return_value = mock_response = Mock()
    mock_response.status_code = 200

    # Act:
    c = client.Client()
    response = c._queryAPI("path", 'GET', {}, None, {})

    # Assert:
    self.assertEqual(response.status_code, 200)

# Repeat the same test for 'POST' queries.

为了测试 getContext(),使用 httpretty 模拟 HTTP...

@httpretty.activate
def testGetContextReturnFields(self):
  """
  Tests client.getContext() for a sample term.
  Asserts the returned object contains the corrcet fields and have contents as
  expected.
  """
  # Arrange: mock JSON response from API, mock out the API endpoint we expect
  # to be called.
  mockResponseString = getMockApiData("context_foo.json")
  httpretty.register_uri(httpretty.GET,
                         "http://this.is.the.url/query",
                         body=mockResponseString,
                         content_type="application/json")

  # Act: create the client object we'll be testing.
  c = client.Client()
  contexts = c.getContext("foo")

  # Assert: check the result object.
  self.assertTrue(isinstance(contexts, list),
    "Returned object is not of type list as expected.")
  self.assertTrue(("context_label" and "context_id") in contexts[0], 
    "Data structure returned by getContext() does not contain"
    " the required fields.")
  self.assertTrue(isinstance(contexts[0]["context_label"], str),
    "The \'context_label\' field is not of type string.")
  self.assertEqual(contexts[0]["context_id"], 0,
    "The top context does not have ID of zero.")

【讨论】:

    猜你喜欢
    • 2021-04-12
    • 1970-01-01
    • 2020-11-26
    • 2022-01-22
    • 1970-01-01
    • 2018-08-09
    • 2020-06-20
    • 2015-05-10
    • 2019-11-24
    相关资源
    最近更新 更多