If you know Kotlin, or at least you have heard something about Kotlin, you know extension methods. But one important question with extension methods is how to use it, while not abusing it? I present you: one concrete example for abuse.

I was using MockWebServer, nice library for mocking server that works with Android instrumented tests. I was doing stuff that should be repeated in many tests, so I extracted some set up behavior to seperate methods, obviously. I want my test code to be as readable as possible (duuuh), so I decided to make some extension methods for MockWebServer. Finally I created file ServerExtensions:

private fun okResponse() = MockResponse().setResponseCode(200)

fun MockWebServer.respondingWithOk(action: (RecordedRequest) -> Unit) {
    setDispatcher(object : Dispatcher() {
        override fun dispatch(request: RecordedRequest): MockResponse {
            action(request)
            return okResponse()
        }
    })
}

fun MockWebServer.respondWithOk() {
    setDispatcher(object : Dispatcher() {
        override fun dispatch(request: RecordedRequest) = okResponse()
    })
}

fun MockWebServer.onCorrectRequest(action: () -> Unit) {
    respondingWithOk { request -> if (isCorrectRequest(request)) action() }
}

fun MockWebServer.takeRequests(requestCount: Int): List<RecordedRequest> {
    return (1..requestCount).map { takeRequest(10, SECONDS) }
}

If you look at it… looks reasonable, it wraps in methods some boilerplate code that you can easily reuse.

Seems legit

But then I had to add another method to it and I noticed that I already have a few extension methods for just one class. And it seems that I will have to add more in the nearest future. In short, it turned out that interface of this object just doesn’t fit my usage. Which is totally normal - interface of the library should be really generic.

But it striked me what I was doing - I wasn’t really adding some missing functionality, I was building my own interface for this object. So maybe, just maybe… I should simply create new interface for it?

Of course. That’s why adapter pattern is for. And no, you don’t need to name it *Adapter - think about domain name for such object, so tests are even more readable.

class ClientServerMock {

    val server = MockWebServer()

    public fun respondingWithOk(action: (RecordedRequest) -> Unit) {
        server.setDispatcher(object : Dispatcher() {
            override fun dispatch(request: RecordedRequest): MockResponse {
                action(request)
                return okResponse()
            }
        })
    }

    public fun respondWithOk() {
        server.setDispatcher(object : Dispatcher() {
            override fun dispatch(request: RecordedRequest) = MockResponse()
        })
    }

    fun onCorrectRequest(action: () -> Unit) {
        respondingWithOk { request -> if (isCorrectRequest(request)) action() }
    }

    fun takeRequests(requestCount: Int): List<RecordedRequest> {
        return (1..requestCount).map { server.takeRequest(10, TimeUnit.SECONDS) }
    }
}

Feels sooo good. You have proper object (instead of bunch of functions laying around), more people can understand your code and by introducing new class name, you just made your code more readable. You can’t ask for more.

TL;DR

If you are adding many extension methods to one class, you should probably make some kind of adapter for that class.