apple / app-store-server-library-python

MIT License
168 stars 31 forks source link

Support stubbing AppStoreServerAPIClient for unit tests #24

Open WFT opened 1 year ago

WFT commented 1 year ago

Feature request: I'd like the ability to create mock responses to API client calls which will be returned by the next call to a specific client method.

Use case

I would like to do unit testing for my server's use of the library. I want to test the following features of my server:

  1. Customer service requests to extend subscription renewals
  2. Requests to get the latest subscription status of a customer (e.g. for testing my handling of older clients with ReceiptUtility)

Example code

Here's an example test one could write:

from appstoreserverlibrary import testing as appstore

replace_server_api_client(appstore.TestingAPIClient(...))

def test_customer_service_extension(client):
    def callback(original_transaction_id: str, extend_renewal_date_request: ExtendRenewalDateRequest) -> ExtendRenewalDateResponse:
        assert stuff_about_the_request(original_transaction_id, extend_renewal_date_request)
        return ExtendRenewalDateResponse(...)

    with appstore.client_stubber as stubber: # Asserts on leaving the `with` that the expected responses were consumed
        stubber.extend_subscription_renewal_date.add_response(callback)
        response = client.post('/api/customer-service/app-store/extend')
        assert response.code == 200

    # Check that our server is properly handling saving the effectiveDate to the database
    response = client.get('/api/app-store/renewal-date')
    assert response.code == 200
    assert has_been_extended(response)
alexanderjordanbaker commented 1 year ago

@WFT currently how the unit tests are constructed, either directly or through subclassing you can override the direct method used to make the HTTP call, do any validation required on the inputs, and then return any arbitrary response

https://github.com/apple/app-store-server-library-python/blob/2d11b06188cd24c4e8751bf1b10de59333c6a819/tests/test_api_client.py#L381-L405, or if you are looking for a higher level override, _make_request can be overridden which takes the request and response before they are parsed to/from JSON. This could be extended I believe to create the stubbed behavior you are describing

WFT commented 1 year ago

@alexanderjordanbaker Yeah I think that makes sense. In my codebase I've just been using a general-purpose HTTP mocking library (https://github.com/gabrielfalcao/HTTPretty -- wish it were a little more maintained). I think that to make a really great testing experience though, it'd be nice if we could get it into this library.