How to mock an api to run your Espresso android tests with Mockwebserver

Android Espresso instrumented test

Most of the time, android apps work with a rest api.

Libs like Retrofit, Koin make it easy to interact with this rest api. However, it’s not so easy when running instrumented tests.

First, we should disable the animations. Otherwise the tests are gonna crash. I haven’t found a better than this one for now.

adb shell settings put global window_animation_scale 0.0
adb shell settings put global transition_animation_scale 0.0
adb shell settings put global animator_duration_scale 0.0

The purpose of the lib MockWebServer is obvioulsy to mock a web server. We can send our requests to mockwebserver instead of the remote rest api. To do that, we only need to change the base url inside our Retrofit Builder.

If you happen to have a set url defined in your config, a product flavor, build type or a config of some kind should do the trick. In my case, base url was dynamic.

With Koin, your dependencies is usually built upon the application create method where you start koin with the modules and possibly your retrofit builders.

The problem is that when android runs your test, whether you’re still using ActivityTestRule or moved to ActivityScenarioRule, the Application’s create method build your whole koin dependency graph and the HomeActivity is launched before the test starts. The dependencies are then injected, so any attempt to override (with loadKoinModules) your module’s retrofit builder dependency in a method with @Before annotation is useless for this activity.

@LargeTest
@RunWith(AndroidJUnit4ClassRunner::class)
class HomeActivityTest {
@Rule
@JvmField
var activityScenarioRule = ActivityScenarioRule(HomeActivity::class.java)

@Test
fun listIsDisplayed() {...}
}

One solution is to override the retrofit dependency when the application is created with the loadKoinModules extension.

It is possible to hook on the Application’s create method inside AndroidJUnitRunner.

With a custom testInstrumentationRunner declared inside the app gradle file.

defaultConfig {

testInstrumentationRunner "com.myPackage.app.ApiTestRunner"
...
}

The application create method is called. Immediately after, we can override any dependency. the override = true parameter is required.

MockWebServer listens to a random port on localhost by default. We will fix a set port to bind our retrofit builder to the mocked web server. We know now which url retrofit should send its requests to.

Before runnning the tests, a mocked server should be up to receive our future incoming request.

In the @Before annotation, MockWebServer is instanciated and started with the prefixed port we defined earlier on. Shutting down the webserver between tests is recommended. It’s possible to use your dependency graph to retrieve a service and make something with it.

Optionnally, we can build our predefined responses from json files instead of strings to increase readability.

A simple class like this does the trick. We store our mocked json responses in a file and return it as a String.

The instrumented tests can start with the full power of MockWebServer. Load the response and return mocked responses when the tested app make a request.

It gives you the power to test how the app behaves with unexpected responses.