Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Robolectric + OkHttp + retrofit + rxJava Unit Test

I'm trying to write a unit test for a piece of code with robolectric. The problem is that I need to fake the http call but seems that robolectric's fake layer it works only with Apache's HttpClient as per this answer:

Link to answer

In Retrofit you can't change the URL so the MockWebServer seems to be not an option.

It seems that mockito can catch the retrofit callbacks but I'm using rxJava so I don't really know if it can helps.

Does anyone has any suggestions about unit testing with Robolectric + Retrofit + okHttp + rxJava?

Here is a small piece of code:

    @Test
public void test1() throws IOException, InterruptedException {
    FragmentA frag = (FragmentA) activity
            .getFragmentManager().findFragmentById(
                    R.id.frag);
    assertThat(frag).isNotNull();
    assertThat(frag.isVisible()).isTrue();

    EditText input1 = (EditText) frag.getView()
            .findViewById(R.id.edit_text1);
    EditText input2 = (EditText) frag.getView()
            .findViewById(R.id.edit_text2);
    Button button = (button) frag.getView()
            .findViewById(R.id.button);
    input1.setText("999");
    input2.setText("999");
    Robolectric.addPendingHttpResponse(200, "{\"isValid\": true}");
    button.performClick();
            assertThat(
            ShadowAlertDialog.getLatestDialog() instanceof ProgressDialog)
            .isTrue();

  }

Robolectric.addPendingHttpResponse won't works anyway because of the OkHttp. The api call is started when the button is pressed so in that I moment I need to fake the response!

like image 371
fedestylah Avatar asked Aug 28 '14 15:08

fedestylah


1 Answers

You can get the server URL from a constant declared in the build.gradle and add a test flavor or buildType that overwrites it

release {
    buildConfigField "String", "SERVER_URL", "\"github.com\""
}
testing {
    buildConfigField "String", "SERVER_URL", "\"127.0.0.1\""
}

Another alternative not Android specific, (less elegant IMHO but it works in all cases) is to use a private variable that is only accessible and usable during testing, using reflection like this:

  1. Create a private static variable that is null, i.e. private static String BASE_URL = null;
  2. Use a method to get the host URL and in that method check whether to use BASE_URL when it's not null (never in the release version) or the URL from the resources (never hard-code the URL in the code)
  3. During testing use reflection to change the private visibility to public and modify the BASE_URL to your testing URL.

To do the reflection part use this example:

final Field urlField = MyService.class.getDeclaredField("BASE_URL");
urlField.setAccessible(true);
urlField.set(null, TEST_URL );
like image 52
Sebas LG Avatar answered Oct 06 '22 09:10

Sebas LG