Warning

This component is an alpha. Interfaces may change outside of the normal semver policy.

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)