Skip to content

MockWebServer for instrumentation tests

Devrath edited this page Jul 4, 2021 · 2 revisions

What is the advantage of using MockWebServer in Instrumentation tests

  • In instrumentation tests, we usually check the views displayed on the screen and the behaviour on operation on any widgets.
  • Usually we call an API and get the data from the server sometimes, Because of this, there is a dependency on an external entity.
  • We will not be able to test in such dependency and when the internet is down or the external entity is down, the tests might fail.

Use of mockserver

  • Using the mock server we can mock the API request to the local mock class and run tests
  • A mock web server is a program that mocks the behavior of an actual remote server but doesn’t make calls over the internet. This makes it easy to test different scenarios without internet access and without having to make changes to your remote server.

Setting up the server

Step-1 : Setting up the application class

object AppConstants {
    const val BASE_URL = "https://raw.githubusercontent.com/devrath/Sample-Data/master/Android-CleanArchitecture-Kotlin/"
}

@HiltAndroidApp
open class AndroidApplication : Application(){
    open fun getBaseUrl() = AppConstants.BASE_URL
}

Step-2 : Provide a point of switch so that the url is accessed from the appication class

Retrofit.Builder()
.baseUrl((application as AndroidApplication).getBaseUrl())
.client(createClient())
.addConverterFactory(GsonConverterFactory.create())
.build()

Step-3 : Define an application class in the test package that extends the application class that we defined in the app earlier.

class AndroidApplicationTest : AndroidApplication() {
  var url = "http://127.0.0.1:8080"
  override fun getBaseUrl(): String {
    return url
  }
}

Step-4 : Define the custom test runner - This test runner has reference to test application we defined earlier

class MockTestRunner : AndroidJUnitRunner() {
    override fun newApplication(cl: ClassLoader?, className: String?,
                                context: Context?): Application {
        return super.newApplication(cl, AndroidApplicationTest::class.java.name, context)
    }
}

Step-5 : Replace this class with the package reference in the manifest for the custom runner in place of the normal runner.

Step-6 : Initilize the mock server and use it

@HiltAndroidTest
@RunWith(AndroidJUnit4::class)
abstract class BaseTest {

    @get:Rule
    var rule = OkHttpIdlingResourceRule()

    val portNumber = 8080

    val mockWebServer = MockWebServer()

    @Before
    @Throws
    fun setup() {
        mockWebServer.start(portNumber)
    }

    @After
    @Throws
    fun teardown() {
        mockWebServer.shutdown()
    }


    fun successfulServerResponse(inputJsonPath : String) {
        mockWebServer.dispatcher = object : Dispatcher() {
            override fun dispatch(request: RecordedRequest): MockResponse {
                return MockResponse()
                    .setResponseCode(200)
                    .setBody(FileReader.readStringFromFile("success_response.json"))
            }
        }
    }

}

class MainActivityTest : BaseTest(){
    @get:Rule
    val activityRule = ActivityTestRule(MainActivity::class.java, true, false)

    @Test
    fun testForSuccessfulResponse() {
        successfulServerResponse("success_response.json")
        activityRule.launchActivity(null)
    }
}
Clone this wiki locally