Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Unit testing the onPageStarted and onPageFinished of a WebView's WebViewClient callbacks

Android Studio 3.5.1
Kotlin 1.3

I have the following method that I am trying to unit test. That uses the WebView and WebViewClient

The method I have is the following that needs to be unit tested:

fun setPageStatus(webView: WebView?, pageStatus: (PageStatusResult) -> Unit) {
    webView?.webViewClient = object : WebViewClient() {

        override fun onPageStarted(view: WebView?, url: String?, favicon: Bitmap?) {
            pageStatus(PageStatusResult.PageStarted(url ?: "", favicon))
        }

        override fun onPageFinished(view: WebView?, url: String?) {
            pageStatus(PageStatusResult.PageFinished(url ?: ""))
        }
    }
}

I takes a webView that overrides some callback from the WebViewClient. And then calls a lambda function in the onPageStarted or onPageFinished.

Uses a sealed class to set the properties that is passed in the lambda method

sealed class PageStatusResult {
    data class PageFinished(val url: String) : PageStatusResult()
    data class PageStarted(val url: String, val favicon: Bitmap?) : PageStatusResult()
}

In the unit test I have do something like this:

@Test
fun `should set the correct settings of the WebView`() {
    // Arrange the webView
    val webView = WebView(RuntimeEnvironment.application.baseContext)

    // Act by calling the setPageStatus
    webFragment.setPageStatus(webView) { pageStatusResult ->
        when(pageStatusResult) {
            is PageStarted -> {
            // Assert that the url is correct
                assertThat(pageStatusResult.url).isEqualToIgnoringCase("http://google.com")
            }
        }
    }

    // Call the onPageStarted on the webViewClient and and assert in the when statement
    webView.webViewClient.onPageStarted(webView, "http://google.com", null)
}
like image 903
ant2009 Avatar asked Oct 18 '19 19:10

ant2009


2 Answers

As the nature of this unit test is async, instead of calling the webView.webViewClient.onPageStarted synchronously yourself, you should use an async testing approach. In this way, we pass a URL to the WebView to show, then wait until the onPageStarted method is called by the WebView itself.

It seems that the best option to run async unit tests in Android is using the Awaitility.

build.gradle

dependencies {
    testImplementation 'org.awaitility:awaitility:4.0.1'
}

Unit Test Class

@Test
fun `should set the correct settings of the WebView`() {

    val requestedUrl = "https://www.google.com"
    var resultUrl: String? = null

    // Arrange the webView
    val webView = WebView(RuntimeEnvironment.application.baseContext)

    // Act by calling the setPageStatus
    webFragment.setPageStatus(webView) { pageStatusResult ->
        when (pageStatusResult) {
            is PageStatusResult.PageStarted -> {
                resultUrl = pageStatusResult.url
            }
        }
    }

    // trying to load the "requestedUrl"
    webView.loadUrl(requestedUrl)

    // waiting until the "onPageStarted" is called
    await().until { resultUrl != null }

    // now check the equality of URLs
    assertThat(resultUrl).isEqualToIgnoringCase(requestedUrl)
}
like image 127
aminography Avatar answered Nov 02 '22 19:11

aminography


If you're using kotlinx-coroutines-test, you could use CompletableDeferred to await.

    @Test
    fun `should set the correct settings of the WebView`() = runTest {
        val urlDeferred = CompletableDeferred<String>(coroutineContext.job)

        // Arrange the webView
        val webView = WebView(ApplicationProvider.getApplicationContext())

        // Act by calling the setPageStatus
        webFragment.setPageStatus(webView) { pageStatusResult ->
            when(pageStatusResult) {
                is PageStatusResult.PageStarted -> {
                    urlDeferred.complete(pageStatusResult.url)
                }
            }
        }

        // Call the onPageStarted on the webViewClient and and assert in the when statement
        webView.webViewClient.onPageStarted(webView, "http://google.com", null)

        // Await at most MAX_WAITING milliseconds
        val url = withTimeout(MAX_WAITING) { urlDeferred.await() }

        // Assert that the url is correct
        assertThat(url).isEqualToIgnoringCase("http://google.com")
    }
like image 1
fikr4n Avatar answered Nov 02 '22 19:11

fikr4n