Skip to content

DroidsOnRoids/mockwebserver-path-dispatcher

Repository files navigation

Javadocs Maven Central

MockWebServer path dispatcher

A helper for dispatching MockWebServer responses. It allows to easily mock responses with data stored in YAML files in resources/fixtures/ directory

Motivation

  • YAML used to store responses for more readability (compared to bare MockWebServer)
  • Android compatible (unlike MockWebServer+)
  • Concise dispatching logic implementation

Example

Code with MockWebServer path dispatcher:

fun pathCondition() {
    val dispatcher = FixtureDispatcher()
    // match all URLs with path starting with /prefix/ e.g. http://example.test/prefix/
    val factory = PathQueryConditionFactory("/prefix/")
    // match all URLs with path ending with "suffix" and return response from fixtures/body_path.yaml
    dispatcher.putResponse(factory.withPathSuffix("suffix"), "body_path")
    dispatcher.putResponse(factory.withPathSuffix("another_suffix"), "json_object")
    mockWebServer.setDispatcher(dispatcher)
}

Example YAML file at resources/fixtures/json_object.yaml:

statusCode : 200
headers:
- 'Content-Type: application/json'
body: >
    {
      "test": null
    }

Instead of defining body in yaml directly you can specify relative path to file with body:

statusCode : 404
headers:
- 'Content-Type: text/plain'
- "Vary: Accept-Encoding"
body: body.txt

You can force the request to fail by setting connectionFailure to true:

statusCode : 200
connectionFailure: true

Alternatively, you can specify not getting a response by simulating a timeout with timeoutFailure to true:

statusCode : 200
timeoutFailure: true

Code without MockWebServer path dispatcher:

fun bareMockWebServer() {
    val dispatcher = object : Dispatcher() {
        override fun dispatch(request: RecordedRequest): MockResponse {
            val path = request.requestUrl.encodedPath()
            if (path == "/prefix/suffix") {
                return MockResponse()
                        .setResponseCode(404)
                        .addHeader("Content-Type", "text/plain")
                        .addHeader("Vary", "Accept-Encoding")
                        .setBody("""{"test"}""")
            } else if (path == "/prefix/another_suffix") {
                return MockResponse()
                        .setResponseCode(200)
                        .addHeader("Content-Type", "application/json")
                        .setBody("{\n  \"test\": null\n}")
            }
            throw IllegalArgumentException("Unexpected request: $request")
        }
    }
    mockWebServer.setDispatcher(dispatcher)
}

See more examples at FunctionalTest.kt

API

FixtureDispatcher - when you want conditional fixture response mapping and enqueuing:

fun factory() {
    val dispatcher = FixtureDispatcher()
    val factory = PathQueryConditionFactory("/prefix/")
    // bar will be served for first matching requests
    dispatcher.enqueue(factory.withPathSuffix("suffix"), "bar")
    // bar will be served for second matching requests
    dispatcher.enqueue(factory.withPathSuffix("suffix"), "baz")
    // foo will be served by default (if there is nothing enqueued) for subsequent matching requests
    dispatcher.putResponse(factory.withPathSuffix("suffix"), "foo")    
    // qux will be served by default when there are no matching requests
    dispatcher.setFallbackResponse("qux")    
    mockWebServer.setDispatcher(dispatcher)
}

PathQueryConditionFactory - when you want to use common URL path prefix multiple times:

fun factory() {
    val dispatcher = FixtureDispatcher()
    val factory = PathQueryConditionFactory("/prefix/")
    dispatcher.putResponse(factory.withPathSuffix("suffix"), "queryless_response")
    // match all URLs with path ending with "suffix" and have "param" with any value as query parameter e.g. http://example.test/prefix/user/suffix?param
    dispatcher.putResponse(factory.withPathSuffixAndQueryParameter("suffix", "param"), "response_with_query_parameter")
    // match all URLs with path ending with "suffix" and have "param" with "value" as query parameter e.g. http://example.test/prefix/user/suffix?param=value
    dispatcher.putResponse(factory.withPathSuffixAndQueryParameter("suffix", "param", "value"), "response_with_query_parameter_and_value")
    // match all URLs with path ending with "suffix" and have multiple parameter name/value pairs e.g.http://example.test/prefix/user/suffix?param=value&param2=value2
    dispatcher.putResponse(
        factory.withPathSuffixAndQueryParameters("suffix", mapOf("param" to "value", "param2" to "value2")),
        "response_with_multiple_query_parameters"
    )
    mockWebServer.setDispatcher(dispatcher)
}

PathQueryCondition - when you want to match by path and optional query parameter:

fun pathQueryCondition() {
    val dispatcher = FixtureDispatcher()
    dispatcher.putResponse(PathQueryCondition("/prefix/suffix", "param", "value"), "response_with_query_parameter_and_value")
    mockWebServer.setDispatcher(dispatcher)
    
}

Also supports a map of multiple query parameters:

fun pathQueryConditions() {
    val dispatcher = FixtureDispatcher()
    dispatcher.putResponse(PathQueryCondition("/prefix/suffix", mapOf("param" to "value", "param2" to "value2")), "response_with_query_parameters_and_values")
    mockWebServer.setDispatcher(dispatcher)
}

HttpUrlCondition - when you want to match by some part of URL other than path or single query parameter:

fun httpUrlCondition() {
    val dispatcher = FixtureDispatcher()
    val condition = object : HttpUrlCondition() {
        override fun isUrlMatching(url: HttpUrl) = url.encodedUsername() == "foo"

        override fun compareTo(other: Condition) = 0
    }
    dispatcher.putResponse(condition , "response_for_foo")
    mockWebServer.setDispatcher(dispatcher)    
}

Condition - when you want to match by non-URL parts of the request e.g. headers:

fun condition() {
    val condition = object : Condition {
        override fun isRequestMatching(request: RecordedRequest)= request.getHeader("Content-Type") == "application/json"

        override fun compareTo(other: Condition) = 0
    }
    dispatcher.putResponse(condition , "json_response")   
}

Download

For unit tests:

testImplementation 'pl.droidsonroids.testing:mockwebserver-path-dispatcher:1.1.7'

or for Android instrumentation tests:

androidTestImplementation 'pl.droidsonroids.testing:mockwebserver-path-dispatcher:1.1.7'

License

Library uses the MIT License. See LICENSE file.