Mocking GraphQL responses (experimental)
QueueTestNetworkTransport
is a high-level test API that enables you to specify the GraphQL responses that are returned by your ApolloClient
instance.
See also
MockServer
, which creates a full HTTP server and helps test specific server behaviors, such as error cases, HTTP headers, and timeouts.
Add the dependency to your project's build.gradle
file:
1dependencies {
2 testImplementation("com.apollographql.apollo3:apollo-testing-support:3.8.5")
3}
4
5// Also add jcenter() to your repositories
6// See https://github.com/Kotlin/kotlinx-nodejs/issues/16
7repositories {
8 mavenCentral()
9 jcenter()
10}
Enable the QueueTestNetworkTransport
by passing it to the ApolloClient
builder:
1val apolloClient = ApolloClient.Builder()
2 .networkTransport(QueueTestNetworkTransport())
3 .build()
You can then use the enqueueTestResponse
extension function to specify the GraphQL responses to return:
1val testQuery = GetHeroQuery("001")
2val testData = GetHeroQuery.Data {
3 hero = droidHero {
4 name = "R2D2"
5 }
6}
7apolloClient.enqueueTestResponse(testQuery, testData)
8
9val actual = apolloClient.query(testQuery).execute().data!!
10assertEquals(testData.hero.name, actual.hero.name)
You can pass an ApolloResponse
to the enqueueTestResponse
function, or as a shortcut, you can pass a Data
directly as shown above. If you do pass a Data
, you also need to pass an operation, because an ApolloResponse
is built under the hood, which needs a reference to it.
To help create your mocked response data, you can use test builders.
Advanced usage
QueueTestNetworkTransport
returns responses in the order they've been enqueued.
In certain tests, it might be more convenient to map responses to operations.
To achieve this, use MapTestNetworkTransport
instead and call the registerTestResponse
extension function:
1val apolloClient = ApolloClient.Builder().networkTransport(MapTestNetworkTransport()).build()
2
3apolloClient.registerTestResponse(query1, testData1)
4apolloClient.registerTestResponse(query2, testData2)
5
6val actual1 = apolloClient.query(query1).execute().data
7val actual2 = apolloClient.query(query2).execute().data
8// Execute query1 again, which is mapped to testData1
9val actual3 = apolloClient.query(query1).execute().data
10
11assertEquals(testData1, actual1)
12assertEquals(testData2, actual2)
13assertEquals(testData1, actual3)
If you need more control over the responses to return, you can implement your own NetworkTransport
and pass it to the ApolloClient
builder:
1private class CustomTestNetworkTransport : NetworkTransport {
2 override fun <D : Operation.Data> execute(request: ApolloRequest<D>): Flow<ApolloResponse<D>> {
3 return flowOf(
4 ApolloResponse.Builder(
5 /* Your custom logic here */
6 ).build() as ApolloResponse<D>
7 )
8 }
9
10override fun dispose() {}
11}
12
13apolloClient = ApolloClient.Builder()
14 .networkTransport(CustomTestNetworkTransport())
15 .build()
Note that if you use a custom NetworkTransport
, calling enqueueTestResponse()
or registerTestResponse()
is no longer possible because they expect the transport to be QueueTestNetworkTransport
or MapTestNetworkTransport
.