Getting Started with _testing

Dependencies

This toolchain requires the responses library.

globus_sdk._testing is tested to operate with the latest version of responses.

Usage

Activating Individual Responses

Once responses has been activated, each response fixture can be loaded and activated by name:

from globus_sdk._testing import load_response

# load_response will add the response to `responses` and return it
load_response("auth.get_identities")
# "case" is used to have a single name map to multiple responses
data = load_response("auth.get_identities", case="multiple")

Responses can also be activated by passing an SDK client method, bound or unbound, as in:

import globus_sdk
from globus_sdk._testing import load_response

load_response(globus_sdk.AuthClient.get_identities)
load_response(globus_sdk.AuthClient.get_identities, case="unauthorized")

# or, with a bound method
ac = globus_sdk.AuthClient()
load_response(ac.get_identities, case="multiple")

Activating “Scenarios”

Some sets of fixtures may describe a scenario, and therefore it’s desirable to load all of them at once:

from globus_sdk._testing import load_response_set

fixtures = load_response_set("scenario.foo")

Getting Responses and ResponseSets without Activating

If you want to fetch a ResponseSet or RegisteredResponse without activating it, you can do this via the get_response_set method. Responses must always be part of a response set, and the default name for an individual response is "default".

from globus_sdk import AuthClient
from globus_sdk._testing import get_response_set

# rset will not be activated
rset = get_response_set(AuthClient.get_identities)
# you can get an individual response from rset
get_ids = rset.get("default")
# you can manually activate a whole set
rset.activate_all()
# or just one response from it by name
rset.activate("default")

Note that activating a whole response set may or may not make sense. For example, the response set for AuthClient.get_identities provides various responses for the same API call.

Registering Response Sets

You can register your own response sets dynamically, and then load them up with the same load_response_set method. Note that custom response sets will override the builtin response sets, if names match.

from globus_sdk._testing import load_response_set, register_response_set
import uuid

# register a scenario under which Globus Auth get_identities and Globus
# Transfer operation_ls both return payloads of `{"foo": "bar"}`
# use an autogenerated endpoint ID and put it into the response metadata
# register_response_set takes dict data and converts it to fixtures
endpoint_id = str(uuid.uuid1())
register_response_set(
    "foobar",
    {
        "get_identities": {
            "service": "auth",
            "path": "/v2/api/identities",
            "json": {"foo": "bar"},
        },
        "operation_ls": {
            "service": "transfer",
            "path": f"/operation/endpoint/{endpoint_id}/ls",
            "json": {"foo": "bar"},
        },
    },
    metadata={
        "endpoint_id": endpoint_id,
    },
)

# activate the result, and get it as a ResponseSet
fixtures = load_response_set("foobar")
# you can then pull the epid from the metadata
epid = fixtures.metadata["endpoint_id"]
transfer_client.operation_ls(epid)

register_response_set can therefore be used to load fixture data early in a tetstsuite run (e.g. as an autouse session-level fixture), for reference later in the testsuite.

Loading Responses without Registering

Because RegisteredResponse takes care of resolving "auth" to the Auth URL, "transfer" to the Transfer URL, and so forth, you might want to use globus_sdk._testing in lieu of responses even when registering single responses for individual tests.

To support this mode of usage, load_response can take a RegisteredResponse instance, and load_response_set can take a ResponseSet instance.

Consider the following example of a parametrized test which uses load_response(RegisteredResponse(...)) as a replacement for responses.add:

from globus_sdk._testing import load_response, RegisteredResponse
import pytest


@pytest.mark.parametrize("message", ["foo", "bar"])
def test_get_identities_sends_back_strange_message(message):
    load_response(
        RegisteredResponse(
            service="auth",
            path="/v2/api/identities",
            json={"message": message},
        )
    )

    ac = globus_sdk.AuthClient()
    res = ac.get_identities(usernames="foo@example.com")
    assert res["message"] == message

In this mode of usage, the response set registry is skipped altogether. It is not necessary to name or organize the response fixtures in a way that is usable outside of the specific test.

Using non-default responses.RequestsMock objects

By default, all methods in globus_sdk._testing which converse with responses use the default mock. This is the behavior offered by responses.add(...) and similar methods.

However, you can pass a custom RequestsMock if so desired to the following methods:

  • get_last_request

  • load_response_set

  • load_response

as a keyword argument, requests_mock. e.g.

from globus_sdk._testing import get_last_request
import responses

custom_mock = responses.RequestsMock(...)
...

get_last_request(requests_mock=custom_mock)