Testing REST APIs Using MockWebServer

Learn how to mock a REST API with MockWebServer and easily test your business logic using Espresso to check how your UI handle success or error responses. By Subhrajyoti Sen.

3.5 (2) · 2 Reviews

Download materials
Save for later
Share
Update note: Subhrajyoti Sen updated this tutorial to use a working API. Subhrajyoti Sen also wrote the original tutorial.

MockWebServer is a library from Square, the people who made Retrofit and OkHttp. MockWebServer allows you to easily test how your apps behave when making HTTP/HTTPS calls.

A mock web server is a program that simulates the behavior of an actual remote server but doesn’t make calls over the internet. This makes it easy to test scenarios without internet access and without having to alter your remote server.

In this tutorial, you’ll learn:

  • The benefits of using a mock server while testing.
  • How to set up MockWebServer.
  • How to make MockWebServer mock the behavior of your actual server.
  • How to write UI tests to make sure your app functions as expected.

You’ll do this by working on a What’s The Meme app, which displays a list of popular meme templates and their names.

Getting Started

Download the starter project by using the Download Materials button at the top or bottom of the tutorial.

You’ll find a starter project and a final project inside the materials.

Some of the files in the starter project are:

  1. MemeAdapter.kt: A RecyclerView adapter that displays the list of memes.
  2. MemeModel.kt: A Kotlin data model that represents each meme.
  3. MainActivity.kt: Displays the list and the error states, when required.
  4. MainViewModel.kt: Interacts with MemeRepository and emits state to MainActivity.
  5. OkHttpProvider.kt: Contains a helper method to access a networking client.
  6. MemeApi.kt: Contains a method corresponding to the API call you want to make.

In this tutorial, you’ll focus less on the code from the files above and more on setting up MockWebServer and writing tests.

Open Android Studio and select Open an existing Android Studio project. Select starter from the materials folder.

Select the starter project from the download materials folder

After you’ve imported the starter project, build and run. You’ll see a screen like this:

Starter project initial screen

Why Use a Mock Server to Test API Calls?

Before setting up your MockWebServer, you might wonder why you’d want to test your API calls.

Doing this provides a few advantages:

Sometimes, the API might give responses that aren’t straightforward to serialize and deserialize directly. In other cases, you might want to convert the data from your API response from one data type to another. For example, the API might return dates as Strings, but you want to use them as DateTime objects.

For such cases, you might write an adapter to convert the data. A mock web server makes it easy to test whether these adapters are working as expected when making API calls.

It can be tricky to test whether apps handle empty and error states properly when dealing with a remote server. Servers are designed to be as reliable as possible, making it challenging to get error responses while testing. Using a mock server lets you easily emulate error responses and see if the app handles them correctly without changing your actual server.

  1. Testing Adapters Is Easy
  2. Testing Empty and Error States

Why Use MockWebServer Over Manual Client Mocking?

Now that you’re sold on testing your API calls, you might wonder why you should use MockWebServer when you could just mock out whatever class makes your API calls. Here are a few reasons:

  • MockWebServer exercises the full HTTP stack, which would be tedious to do manually.
  • You don’t need to make changes on the app side when using a MockWebServer.
  • It’s easy to recreate edge-cases such as throttling and rare error codes.

Configuring MockWebServer

In this section, you’ll save a response to a JSON file and configure a MockWebServer instance to return the saved response.

Changing the API URL

The base URL for the app is stored in MemeApp. Open MemeApp.kt and look for the following function:

open fun getBaseUrl() = "https://api.imgflip.com"

When you create a test with a mock server, the app shouldn’t use the real URL. Instead, it should use the mock server’s URL. To set this up, you’ll need a mechanism to tell the app to use the real URL usually but the mock URL when you run tests.

A test runner makes this possible. It helps you configure the conditions you use to run your tests.

First, you must create an equivalent of MemeApp that returns the mock URL instead of the real URL.

Do this by creating a file in the androidTest folder and naming it MemeTestApp.kt. Add the following code to it:

package com.company.android.whatsthememe

class MemeTestApp : MemeApp() {  

  var url = "http://127.0.0.1:8080"  
 
  override fun getBaseUrl(): String {  
    return url  
  }  
}

Here, http://127.0.0.1 is the local URL of your computer and 8080 is the port MockWebServer will use.

After you add the MemeTestApp.kt file, your package structure should look like this:

Package structure

Creating a Test Runner

Now, you need to provide a test runner that uses MemeTestApp instead of MemeApp when running a test.

Create a file in the androidTest folder and name it MockTestRunner.kt. Add the following code to it:

package com.company.android.whatsthememe

import android.app.Application
import android.content.Context
import androidx.test.runner.AndroidJUnitRunner

class MockTestRunner : AndroidJUnitRunner() {

  override fun newApplication(cl: ClassLoader?, className: String?,
                              context: Context?): Application {
    return super.newApplication(cl, MemeTestApp::class.java.name, context)
  }
}

newApplication() provides the application instance you’ll use in the test. You can see it returns an application instance using MemeTestApp instead of MemeApp.

Now that you’ve written a test runner, you need to tell Gradle to use it for your project. To do this, open the app-level build.gradle and change the value of testInstrumentationRunner as follows:

testInstrumentationRunner "com.company.android.whatsthememe.MockTestRunner"

Click Sync Now and let Gradle finish syncing. From now on, Gradle will use MockTestRunner whenever you run any UI tests.

To use a mock web server and verify that it’s working as expected, you’ll write a few Espresso tests next.

Using Espresso

Espresso is a testing framework that Android provides to write UI tests. It allows you to emulate user interactions while running tests and verify if your views respond as expected.

You can test MockWebServer even without Espresso. But this tutorial uses it to demonstrate a complete testing scenario.

Note: If you’re new to UI testing using Espresso, check out this introduction to Espresso tutorial.

Before starting to write the test, it’s helpful to review the contents of activity_main.xml. It contains three main views:

  • ProgressBar: Displays the loading status.
  • TextView: Shows the error message.
  • RecyclerView: Displays the list of characters.

Create a file MainActivityTest.kt in the androidTest folder and add this to it:

package com.company.android.whatsthememe

import androidx.test.ext.junit.runners.AndroidJUnit4  
import org.junit.After  
import org.junit.Before  
import org.junit.runner.RunWith

@RunWith(AndroidJUnit4::class)  
class MainActivityTest {  

  @Before  
  fun setup() {  
  }

  @After  
  fun teardown() {
  }
}

This is the basic structure of an Espresso test. You annotate a class with @RunWith(AndroidJUnit4::class) to specify that AndroidJUnit4 is the runner for this test.

A Before annotation on a method specifies that the method will run before every test. Any method with @After will run after every test. Use these annotations to keep initialization logic common to all tests.