BoltzmannBrain
BoltzmannBrain

Reputation: 5412

Python unittest mock an API key

I'm writing unit tests for the Client class of client.py, which queries an API. Each test instantiates the client with c = client.Client("apikey"). Running one test at a time works fine, but running them all (e.g. with py.test) I get a 401: "Exception: Response 401: Unauthorized Access. Requests must contain a valid api-key."

I have a valid API key but this should not be included in the unit tests. I would appreciate an explanation of why "apikey" works for only one query. More specifically, how can I mock out the calls to the API? Below is an example unit test:

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

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

Upvotes: 1

Views: 3001

Answers (1)

BoltzmannBrain
BoltzmannBrain

Reputation: 5412

Separate out the tests for API calls and for the Client.getContext() method. For explicitly testing the API calls, patch a request object...

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.

And for testing getContext(), mock out the HTTP with httpretty...

@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.")

Upvotes: 2

Related Questions