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
.
Recommended Fixtures#
Under pytest, this is the recommended fixture for setting up responses and guaranteeing that requests are sent to the production hostnames:
@pytest.fixture(autouse=True)
def mocked_responses(monkeypatch):
responses.start()
monkeypatch.setitem(os.environ, "GLOBUS_SDK_ENVIRONMENT", "production")
yield
responses.stop()
responses.reset()
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)