andrzejchm / RESTMock

HTTP Server for Android Instrumentation tests
https://medium.com/@andrzejchm/ittd-instrumentation-ttd-for-android-4894cbb82d37#.uir3loxu7
Apache License 2.0
756 stars 58 forks source link

RequestMatcher not working #57

Closed nomisRev closed 7 years ago

nomisRev commented 7 years ago

Hi, I'm using RESTMock and I'm loving it. But I was trying to mock GET request with path matchers but I always got MOCK ERRORS. When I'm doing a simple request to http://test-server.org/get/true and I add a matcher pathEndsWith("true") I get a NOT MOCKED ERROR. The exact same request but without the pathEndsWith("true") works. See example below with logs.

whenGET(pathEndsWith("true")).thenReturnFile(RESTMOCK_GET_PATH_URL)
D/RESTMock: ## Adding new response for: (HTTP method is: GET and url ends with: true)
D/OkHttp: --> GET http://test-server.org/get/true http/1.1
D/OkHttp: --> END GET
D/RESTMock: -> New Request: GET / HTTP/1.1
E/RESTMock: <- Response ERROR:  NOT MOCKED: GET / HTTP/1.1
D/OkHttp: <-- 500 Server Error http://localhost:36316/ (4ms)
D/OkHttp: Content-Length: 10
D/OkHttp: NOT MOCKED
D/OkHttp: <-- END HTTP (10-byte body)
I/MockWebServer: MockWebServer[36316] received request: GET / HTTP/1.1 and responded: HTTP/1.1 500 Server Error
whenRequested(isGET()).thenReturnFile(RESTMOCK_GET_PATH_URL)
D/RESTMock: ## Adding new response for: HTTP method is: GET
D/OkHttp: --> GET http://test-server.org/get/true http/1.1
D/OkHttp: --> END GET
D/RESTMock: -> New Request: GET / HTTP/1.1
D/RESTMock: <- Response:    HTTP/1.1 200 OK
I/MockWebServer: MockWebServer[40123] received request: GET / HTTP/1.1 and responded: HTTP/1.1 200 OK
D/OkHttp: <-- 200 OK http://localhost:40123/ (5ms)
D/OkHttp: Content-Length: 27
D/OkHttp: {  "getIsSuccessful": true}
D/OkHttp: <-- END HTTP (27-byte body)
andrzejchm commented 7 years ago

@nomisRev I've created a sample androidTest:

    @Test
    public void issue57test() throws IOException {
        RESTMockServer.whenGET(pathEndsWith("true")).thenReturnString(200, "{\"getIsSuccessful\": true}");
        HttpLoggingInterceptor loggingInterceptor = new HttpLoggingInterceptor();
        loggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY);

        OkHttpClient okHttpClient = new OkHttpClient.Builder()
                .addInterceptor(loggingInterceptor)
                .build();

        okhttp3.Response response = okHttpClient
                .newCall(new Request.Builder().url(RESTMockServer.getUrl() + "get/true").build())
                .execute();

        assertEquals(200, response.code());
    }

and the result was:

D/OkHttp: --> GET http://localhost:59290/get/true http/1.1
D/OkHttp: --> END GET
D/RESTMock: -> New Request: GET /get/true HTTP/1.1
D/RESTMock: <- Response:    HTTP/1.1 200 OK
I/MockWebServer: MockWebServer[59290] received request: GET /get/true HTTP/1.1 and responded: HTTP/1.1 200 OK
D/OkHttp: <-- 200 OK http://localhost:59290/get/true (13ms)
D/OkHttp: Content-Length: 25
D/OkHttp: {"getIsSuccessful": true}
D/OkHttp: <-- END HTTP (25-byte body)

As far as I can see, your okhttp makes request to http://test-server.org/get/true while it should be doing a request to http://localhost:36316/get/true. Did you remember to set up RESTMock's base url as your request's base url?

nomisRev commented 7 years ago

As suggested for Retrofit 2 I am working with an Interceptor to change the url at runtime. There was something wrong with the Interceptor and it dropped it's scheme.

In case any1 is interested in the interceptor.

/**
 * OkHttp Interceptor allows us easily change base url in the integration and functional tests!
 *
 * https://github.com/square/retrofit/blob/master/samples/src/main/java/com/example/retrofit/DynamicBaseUrl.java
 */
class ChangeableBaseUrlInterceptor : Interceptor {
    @Volatile private var host: HttpUrl? = null

    fun setHost(url: String) {
        this.host = HttpUrl.parse(url)
    }

    @Throws(IOException::class)
    override fun intercept(chain: Interceptor.Chain): Response {
        val newRequest = host?.let {
            val newUrl = chain.request().url().newBuilder()
                    .scheme(it.scheme())
                    .host(it.url().toURI().host)
                    .port(it.port())
                    .build()

            return@let chain.request().newBuilder()
                    .url(newUrl)
                    .build()
        }

        return chain.proceed(newRequest)
    }
}