MockWebServer from guys from Square is awesome and I use it on the daily basis. But there is one thing that would seem pretty obvious - MockWebServer returns default response, right? So you don’t need to mock EVERYTHING, right? Well, not. But I found pretty easy fix.

I get it - MockWebServer was designed in such a way that it requires you to specify exactly what should be returned at which URL. If you didn’t do that, there might be something wrong with your tests. It’s understandable.

But in most cases I’d definitely prefer to have one of these two options:

  1. Return 200 OK for every request that was not defined (because sometimes there might be a lot of them and some might be not important for particular test case)
  2. Return 404 NOT FOUND for every request that was not defined

Currently connection times out, which might make some test unnecessarily slow. These tests are broken, right, but I would rather now that sooner than later. And waiting several seconds for failure in many cases seems overkill.

Let’s say we have cat server API like that:

interface CatsServerApi {

    @POST("cats/images")
    fun sendCatImages(@Body images: List<CatImage>): Call<Void>
}

If you write test like this, it will time out:

@Test
fun `sending cat images has correct url`() {
    catsServer.sendCatImages(listOf(CatImage("google.com/cat.jpg", BRITISH)))

    assert(server.takeRequest().path.endsWith("cats/images"))
}

So we add server.enqueue(MockResponse()) and test passes!

But then we want to have another request in single test:

@Test
fun `sending cat images has correct url every time`() {
    server.enqueue(MockResponse())

    catsServer.sendCatImages(listOf(CatImage("google.com/cat.jpg", BRITISH)))
    assert(server.takeRequest().path.endsWith("cats/images"))

    catsServer.sendCatImages(listOf(CatImage("google.com/cat.jpg", BRITISH)))
    assert(server.takeRequest().path.endsWith("cats/images"))
}

Of course above test fails, because after enqueued response is used once, it is discarded immediately. We could easily test it by doing server.enqueue(MockResponse()) twice or setting our own dispatcher. But what if we want to have default value but we also want to be able to “enqueue” our custom response? Usually we would end up with something like this:

val dispatcher = object : Dispatcher() {

    val defaultResponse = MockResponse()

    var response: MockResponse? = null

    override fun dispatch(request: RecordedRequest?): MockResponse {
        return if (response == null) defaultResponse else response!!
    }
}
server.setDispatcher(dispatcher)

It’s not terrible, right? Then you just need to set dispatcher.response = MockResponse(). Yes, it’s not terrible. But! Firstly, there are more complicated scenarios than this and secondly - it’s pretty big piece of code for easy task.

As it turns out, MockWebServer itself contains dispatcher that has exactly required behaviour - can enqueue many responses but at the same time can have default response set. It is called…

QueueDispatcher

It has two handy methods:

  1. public void setFailFast(MockResponse failFastResponse) - sends response that will be returned immediately, if response queue is empty
  2. public void setFailFast(boolean failFast) - if called with true it will return HTTP 404 if there is no response in queue.

So instead of defining our own dispatcher and setting response manually, we can simply do:

val queueDispatcher = QueueDispatcher()
queueDispatcher.setFailFast(MockResponse())
server.setDispatcher(queueDispatcher)

what is awesome, enqueuing requests works as always:

server.enqueue(MockResponse().setBody("""
          [{"url":"google.com/cat.jpg","breed":"BRITISH"}]
          """))

But this time, without calling enqueue we don’t have timeout, but HTTP 200 OK response.

Nothing more to add, just a quick tip that hopefully saves you some time in the future.

As I was playing with MockWebServer for the purpose of this article I created sample project which you can see here: mockwebserver-default-response. For comparison see BadCatServerTest and GoodCatServerTest.