Skip to content

Instantly share code, notes, and snippets.

@thexande

thexande/blog.md Secret

Created December 20, 2018 05:03
Show Gist options
  • Save thexande/d5be6dd937f96a9fbec3e6f881b63dba to your computer and use it in GitHub Desktop.
Save thexande/d5be6dd937f96a9fbec3e6f881b63dba to your computer and use it in GitHub Desktop.

The guide to unit testing in Swift with Apollo and GraphQL Part 2

How To Mock Apollo within unit tests πŸš€

Now that we have a functioning swift service which returns us name-spaced domain models, we can design a testing strategy for this class. First, we want to consider if mocking GraphQL fully is worth it to you. For example, could just you create a mock object which conforms to ApolloInterface, and write your unit tests from there.

Instead, we are going to mock the Apollo client, and actually execute the Apollo queries with stubbed raw JSON. This is ideal because we actually test how our code interacts with Apollo. Additionally, you can use the JSON and the mocked NetworkTransport object to simulate failed network or parsing states within unit testing, allowing us to gain more test coverage over the World.Store networking object.

This testing strategy is borrowed from the Apollo-iOS test suite, which you can view the source for here .

First, let's look at the mocked NetworkTransport object:

https://gist.github.com/875296283fcc0d7977bfe42dd9b95e1d

This class provides a mocked networking operation utilizing Dispatch to simulate an asynchronous network process. You can also simulate a network failure.

Next, let's add some mocked components for Apollo. We will start with the cache.

https://gist.github.com/b43a77daf0f43fa8d2a16741386fd248

This class allows us to simulate the Apollo cache, and we can actually initialize this object with raw JSON to represent the cache state at the beginning of our unit test. This is useful for testing Apollo's different caching strategies. Here are the caching policies available to you with Apollo, and each caching strategies descriptions.

https://gist.github.com/58cffbe53fba642f8202d8aaa62b3b8e

We could potentially call our service methods with any of the below caching policies, and we may want to make sure that using .fetchIgnoringCacheData actually returns from the network as apposed to the cache.

We won't go over having an initial cache state in this article.

Next, we will add the cache provider class. This object provides us with the ability to configure the mock cache object asynchronously.

https://gist.github.com/c50915f46a079f06ee3266eca9d2349c

In order to actually use this mocked ApolloClient within a test, let's extend XCTestCase for connivence. This will make our mocked client easily accessible within our unit tests.

https://gist.github.com/ee295c477925118bfa6a1f30688258ed

Now that we have our components to mock the ApolloClient together, we need to create the resources which the server would return normally to Apollo. This data will consist of JSON, with a few added properties.


Fetching raw data from a GraphQL server πŸš› πŸ“¦

At its core, the GraphQL server just returns a JSON payload through POST requests. In order to get this data, let's use the bash command curl to send a post request to the GraphQL server to retrieve the raw JSON.

https://gist.github.com/d19d5f760e1dfe630ce628ef3e0c087d

This yields a JSON string which you can put through a formatter, or just pipe the result of this curl command to jq for json formatting.

https://gist.github.com/6d61fa28dddd80a327984431cfe62e42

Be sure to ensure you have added a __typename key within the GraphQL query. If you forget to add the __typename key, Apollo will fail to parse your JSON data.

From there, we add our server returned JSON payload into the mock GraphQL query enum . The cases of this enum represent the queries we could be making, and this allows us to add more queries for testing in the future.

https://gist.github.com/13c7f588966c93524253359c3e151ad8


Actually writing the XCTestCase unit testing class πŸ’―

And now, with all of our required mocked classes and stubbed server JSON, let us write an actual unit test. The first test we write will test a successful network call and parse, this is the application's happy path.

https://gist.github.com/a062d1208d2e5aaf6db63bc08bfd0e58

Next, we will write a test to see what happens when we receive a .network error from an Apollo network failure. This will simulate the phone loosing connection mid call, a network timeout, or another networking related error.

https://gist.github.com/c977e72afbd02e2a9ffcc6bfebd487f0

From there, we add a unit test to check the .parsing error path. This could happen if GraphQL returns invalid JSON to the device. This path needs to be tested because our service code optionally unwraps GraphQL fragments into our domain model objects.

https://gist.github.com/b0a13efb103babffdee12869c983f579

That covers our CountriesQuery GraphQL operation, next we need to write the same 3 tests for our CountryQuery.

https://gist.github.com/e13a4e17841671aeec547306435bcbc4

πŸ˜… That was a lot of tests. We now have 6 unit tests, covering our World.Store object's methods and achieving 97.5% coverage. Not 98%, but close!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment