The following is the first few sections of a chapter from The Busy Coder's Guide to Android Development, plus headings for the remaining major sections, to give you an idea about the content of the chapter.


Testing GraphQL

When we make requests of a GraphQL-powered Web service, it would be nice if our app worked.

Part of ensuring that involves writing tests capable of being run repeatedly, particularly after we make code changes, to confirm that everything works now as it did before those changes. There are a variety of ways of going about writing such tests, and in this chapter, we will explore a few of them, in the context of the Trips/CW/StaticTest sample project.

This chapter is focused on GraphQL-specific issues with testing, particularly when using Apollo-Android. See The Busy Coder’s Guide to Android Development for much more extensive coverage of testing.

Testing Using a Real Server

In many cases, the simplest thing to do is to test your code against a real server. This might be a dedicated test or staging GraphQL server, rather than your production server.

If you are using OkHttp directly, you could perform synchronous GraphQL requests, using execute() instead of enqueue(), as instrumentation test methods are invoked on background threads. Apollo-Android, though, wants to work asynchronously, and that makes things a bit tricky for testing, as you need to block the test method waiting for the work to complete.

There are a variety of ways of implementing this. Since we are using RxJava 2, a simple approach is to use blockingFirst(), which will convert a normally-asynchronous RxJava observer chain into a blocking call:

  @Test
  public void realServer() throws InterruptedException {
    ApolloClient apolloClient=ApolloClient.builder()
      .okHttpClient(new OkHttpClient())
      .serverUrl("https://graphql-demo.commonsware.com/0.3/graphql")
      .build();

    assertResponse(Rx2Apollo.from(apolloClient.query(new GetAllTrips()).watcher())
      .subscribeOn(Schedulers.io())
      .blockingFirst());
  }

The Rx2Apollo setup, through subscribeOn(), is the same as what we might use in the production code. However, rather than setting up an observer and arranging to observe on the main application thread, we just call blockingFirst(). This will block until the background thread starts generating results and return whatever the first result is. This gives us an Apollo-Android Response object for our GetAllTrips.Data, which we can then test to whatever degree we wish. In this sample, the tests are fairly minimal, just enough to prove that this works:

  private void assertResponse(Response<GetAllTrips.Data> response) {
    assertData(response.data());
    assertEquals(0, response.errors().size());
  }

  private void assertData(GetAllTrips.Data data) {
    assertEquals(2, data.allTrips().size());
  }

In this test, we happen to test against the “production” server, to whatever extent this demo server is really “production”. Normally, you would test against some other server, supplying its URL to the ApolloClient.

Mocking the Apollo-Android Response

Testing against a real server works but has limitations:

Another approach for testing is to use a mocking library to set up mock responses from Apollo-Android, such as by using Mockito.

  @Test
  public void mockResponse() {
    GetAllTrips.AllTrip firstTrip=Mockito.mock(GetAllTrips.AllTrip.class);
    GetAllTrips.AllTrip secondTrip=Mockito.mock(GetAllTrips.AllTrip.class);
    ArrayList<GetAllTrips.AllTrip> allTrips=new ArrayList<>();

    allTrips.add(firstTrip);
    allTrips.add(secondTrip);

    GetAllTrips.Data data=Mockito.mock(GetAllTrips.Data.class);

    doAnswer(new Answer() {
      @Override
      public Object answer(InvocationOnMock invocation) throws Throwable {
        return(allTrips);
      }
    }).when(data).allTrips();

    assertData(data);
  }

Here, we:

In this case, the test is fairly pointless, as all we are doing is testing to see if our mocks do what they were told to do. In a larger app, we might pass the mock GetAllTrips.Data object to some business logic, then test the results of that logic.

Note that we are mocking the GetAllTrips.Data, but not the Response object. Apollo-Android marks the Response class as final, and Mockito cannot mock final classes.

Mocking the OkHttp Response

The preview of this section is in an invisible, microscopic font.

Mocking the Server Response

The preview of this section is [REDACTED].