Mock Responses with OkHttp & Retrofit

The Why?

  1. Our tests should run in isolation
  2. Our tests should not be affected by external factors
  3. Our tests conditions are controllable

A flaky test is a test which could fail or pass for the same configuration.

Setup 🔨

testImplementation("com.squareup.okhttp3:mockwebserver:$Version")

Explore 🛫

  • Mocking Responses
  • Throttling for bodies
  • Throttling for headers
  • Many many more

Create the mock web server 🏗

val mockWebServer = MockWebServer()
mockWebServer.start()

Mocking a response

MockResponse()
.setResponseCode(HttpURLConnection.HTTP_OK)
.setBody(""{\"status\":\"error\",\"code\":\"responseCode\"}"
")
mockWebServer.enqueue(mockResponse)

Basic setup for unit tests

class YourTest {
lateinit var mockWebServer: MockWebServer
@Before
fun setUp() {
mockWebServer = MockWebServer()
mockWebServer.start()
}
@After
fun tearDown() {
mockWebServer.shutdown()
}
}

MockWebServer with Retrofit

Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://ourapi.com/")
.build()
public Builder baseUrl(String baseUrl) {
checkNotNull(baseUrl, "baseUrl == null");
return baseUrl(HttpUrl.get(baseUrl));
}
  • Production
HttpUrl.get("https://ourapi.com/")
  • Tests
mockWebServer.url("/")

The Transformation

Before

class OurApi(
private val baseUrl: String = "https://ourapi.com/"
) {
private val retrofit = Retrofit.Builder()
.baseUrl(baseUrl)
.addConverterFactory(MoshiConverterFactory.create())
.build()
}

After

class OurApi(
private val baseUrl: HttpUrl = HttpUrl.get("https://ourapi.com/")
) {
private val retrofit = Retrofit.Builder()
.baseUrl(baseUrl)
.addConverterFactory(MoshiConverterFactory.create())
.build()
}

Bonus 🎉

  1. Create a folder under the following path:~/${MODULE}/src/test/resources
  2. Place there the responses as JSON files such as error.json
  3. From your unit test read the file as a String and pass to the mock web server instance

Read JSON files as Strings

object FileUtils {
fun readTestResourceFile(fileName: String): String {
val fileInputStream = javaClass.classLoader?.getResourceAsStream(fileName)
return fileInputStream?.bufferedReader()?.readText() ?: ""
}
}
// pass to mock web server
val response = MockResponse()
response.setResponseCode(HttpURLConnection.HTTP_OK)
response.setBody(FileUtils.readTestResourceFile("error.json"))

--

--

Android Engineer

Love podcasts or audiobooks? Learn on the go with our new app.

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store