Skip to content

Android Unit Testing API Calls with MockWebServer

It’s no little-known fact that unit testing is a crucial part of development, not only in Android but in pretty much any software development field. The ideal app should have 100% test coverage.

Unit tests are supposed to be small, quick to write and fast to execute. They should also test isolated parts of your code’s logic.

This begs the question, how do we test our API calls without actually making calls to the network?

Introducing MockWebServer

MockWebServer is a library made by Squareup (the guys behind OkHttp and Retrofit) used to fake API calls for testing purposes. You would load in a JSON file that you’ve hardcoded into your app, and enqueue that on an instance of MockWebServer.

After doing that, the server will now know what response to return on the next request it receives.

What are we testing here?

In my experience, you’d use this to test the parsing of a response into a data class (if you’re using automatic POJO parsing with Gson, Jackson, etc.), or your manual deserialisation of a response into said data class.

Add the Dependencies

Add this to your app/build.gradle file.

testImplementation 'com.squareup.okhttp3:mockwebserver:4.3.1'

Add the JSON File

Under your app directory, create another folder called resources if there isn’t one already. Under here, you can put your sample responses here, such as this one.

[
  {
    "userId": 1,
    "id": 1,
    "title": "sunt aut facere repellat provident occaecati excepturi optio reprehenderit",
    "body": "quia et suscipit\nsuscipit recusandae consequuntur expedita et cum"
  },
  {
    "userId": 1,
    "id": 2,
    "title": "qui est esse",
    "body": "est rerum tempore vitae\nsequi sint nihil reprehenderit dolor beatae ea dolores neque"
  }
]

The above code is the same as a response you’d get from the JSONPlaceholder API.

What you can do is make an API call to your own API you want to test (via the browser or Postman), copy that into a separate file you’ll add to your resources folder, and replace any sensitive data such as API keys).

Create a MockResponseFileReader

You’ll need a way of reading your mock API responses during your tests. You can use a helper class I’d like to call MockResponseFileReader.

class MockResponseFileReader(path: String) {

    val content: String

    init {
        val reader = InputStreamReader(this.javaClass.classLoader!!.getResourceAsStream(path))
        content = reader.readText()
        reader.close()
    }

}

This allows you to create an instance of MockResponseFileReader, passing in the path of your mock JSON file, then you’ll be able to grab the content of it like so which you’ll need to pass into your MockWebServer instance.

MockResponseFileReader("jsonplaceholder_success.json").content

Testing with MockWebServer

That’s the set up pretty much done. Now let’s get to the actual test.

In your test class, create an instance of MockWebServer like so.

private val server: MockWebServer = MockWebServer()

Set up your Before and After methods to start and shutdown the webserver, as well as create a Retrofit or whatever you’re using to make calls to that server.

@RunWith(JUnit4::class)
class MockWebUnitTests {

    private val server: MockWebServer = MockWebServer()
    private val MOCK_WEBSERVER_PORT = 8000

    lateinit var placeholderApi: PlaceholderApi
    lateinit var jsonRepository: JsonRepository

    @Before
    fun init() {
        server.start(MOCK_WEBSERVER_PORT)

        placeholderApi = Retrofit.Builder()
            .baseUrl(server.url("/"))
            .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
            .addConverterFactory(GsonConverterFactory.create(Gson()))
            .build()
            .create(PlaceholderApi::class.java)

        jsonRepository = JsonRepository(placeholderApi)
    }

    @After
    fun shutdown() {
        server.shutdown()
    }

}

Then you can enqueue one or more responses during your test. After doing this, whenever an API request is made to the server, it will return that queued response.

@Test
fun `JsonPlaceholder APIs parse correctly`() {
    server.apply {
        enqueue(MockResponse().setBody(MockResponseFileReader("jsonplaceholder_success.json").content))
    }
    jsonRepository.observePosts()
        .test()
        .awaitDone(3, TimeUnit.SECONDS)
        .assertComplete()
        .assertValueCount(1)
        .assertValue { it.size == 2 }
        .assertNoErrors()
}

Pay attention to the order in the queue, as the actual request you make won’t matter. After setting up your MockResponse, you can test your API calls like I’ve done here with my observables.

Get the Source Code

If you want to get your hands dirty and have a play around, the source code can be found here on Github. It’s nothing fancy, just the code above for the most part.

If you like my tutorial here, smash that upvote button, leave a comment, subscribe to my newsletter, share this with your friends, save this in your bookmarks, dump it into Reddit, answer someone’s Quora, publish it in a book, make it your homepage, and as always, happy coding ༼ つ ◕_◕ ༽つ.