apollo-kotlin icon indicating copy to clipboard operation
apollo-kotlin copied to clipboard

What's the preffered way to mock GraphQL responses

Open AKJAW opened this issue 3 years ago • 7 comments

Hello, I was looking through the documentation for Apollo Kotlin v3 and I wasn't able to find anything about how to mock responses for testing.

I was able to find the following resources on the topic:

  1. https://community.apollographql.com/t/mock-apollo-client-on-the-kotlin-multiplatform/221 - This points to classes which were removed since the then
  2. https://techblog.clashapp.co/mocking-apollo-graphql-operations-on-android-c3433051e8a1 - Leverages HttpInterceptors for providing pre-defined data
  3. https://github.com/apollographql/apollo-kotlin/tree/main/apollo-mockserver - I couldn't find much information on this package, only the existing tests in commonTest

I wanted to ask what is the best way to make Apollo return predefined data in testing scenarios. Maybe it would be good to also include this information in the official documentation.

AKJAW avatar Dec 15 '21 14:12 AKJAW

Hi! 👋

Apollo Kotlin 3 introduced test builders which can be used to easily instantiate the generated models in test code - could that help?

BoD avatar Dec 15 '21 16:12 BoD

The test builders would be good for unit tests, however this type of mocking would require replacing the Apollo network layer with a fake that produces these models. This is something I would like to avoid, ideally I'd like to use as much production code as possible in these tests, including the network layer (as far as it is reasonably possible)

AKJAW avatar Dec 15 '21 18:12 AKJAW

Thanks for the clarification. This is indeed an area that we'd like to improve, as we have received several questions on it (see #3681 for instance).

In the meantime, we've just added (#3719 which will be in the next release) a toJson() method that you can call on models built with the Test builders. You could then use it in conjunction with a MockServer for instance.

BoD avatar Dec 15 '21 20:12 BoD

Hi, I was able to get the MockServer and a Mock HttpInterceptor working and I'm wondering if the MockServer could be improved.

Correct me if I'm wrong but currently the MockServer does not map the requests to responses, it only adds them to a queue and depending on the execution order the enqued mock is returned. The HttpInterceptor allows for more granular control because based on the X-APOLLO-OPERATION-NAME header we know the requested operation and we can return the exact mocks for that operation.

This allows mocking a feature / operation without needing to set up the MockServer for every test, and also in cases where the whole feed is not yet completed. Which allows the apps to use the Production and Mock feeds interchangeably, which doesn't force the app developers to wait for the completed feed as they can start building something from the get go.

Would it be possible for the MockServer to allow mapping requests / operations to mocked data without needing to set it up every time? Something like ktor does with its MockEngine, example here

AKJAW avatar Dec 16 '21 07:12 AKJAW

MockServer does not map the requests to responses, it only adds them to a queue

That's correct currently.

About improving MockServer, thanks for the insight! Yes we're certainly thinking of making it less "low level", and more "GraphQL aware", with ways to easily enqueue or map GraphQL responses!

The KTor example you share is useful, thanks (and OkHttp's MockWebServer has a similar idea too), and don't hesitate to share ideas about how an API would look like ideally to be useful in your test!

BoD avatar Dec 16 '21 09:12 BoD

For some context, MockServer was mainly written for our own integration tests because there was no MPP server available (and I think it's still the case?). It's working but also pretty limited in what it can do and its API is not versioned (it's @ApolloExperimental).

If we decide to add a MockWebServer-like dispatcher function, I think it should actually stay at the HTTP level, not GraphQL. We want to be able to mock arbitrary HTTP status code, early connections closures, etc... Users could then use JsonReader to parse the request and get operationName (or use X-APOLLO-OPERATION-NAME from the headers) and apollo-ast if they really want to parse the GraphQL document.

martinbonnin avatar Dec 16 '21 10:12 martinbonnin

Got it, for now I think I'll stick to mocking the responses through HttpInterceptors, it seems to work out alright and as you mentioned it stays in the HTTP level only returning JSONs. Thanks for the answers!

AKJAW avatar Dec 17 '21 21:12 AKJAW

There is now a way to control MockServer responses via MockServerHandler. Closing this issue for now, don't hesitate to re-open if needed!

BoD avatar Nov 03 '22 14:11 BoD