WebViewClient回调的onPageStarted和onPageFinished如何进行单元测试

8
Android Studio 3.5.1
Kotlin 1.3

我有一个需要进行单元测试的方法,它使用了WebViewWebViewClient

我要测试的方法如下:

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 ?: ""))
        }
    }
}

我使用一个重写了WebViewClient的webView,并在onPageStarted或onPageFinished中调用一个lambda函数。

使用密封类来设置传递给lambda方法的属性。

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

在单元测试中,我做了如下操作:
@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)
}
2个回答

4
由于该单元测试的性质是异步的,因此您不应该自己同步地调用webView.webViewClient.onPageStarted,而应该使用异步测试方法。这样做的方式是,我们将一个URL传递给WebView以显示,然后等待WebView自身调用onPageStarted方法。
在Android中运行异步单元测试的最佳选择似乎是使用Awaitilitybuild.gradle
dependencies {
    testImplementation 'org.awaitility:awaitility:4.0.1'
}

单元测试类

@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)
}

1
将URL更改为https,因为在没有网络安全配置的情况下,http可能会失败。 - Martin Zeitler
有没有不使用await()的方法来实现这个?我在想使用doAnswer()或者其他什么东西。 - ant2009
很遗憾,我找不到一种方法可以在等待结果的情况下完成它。 - aminography

1
如果您正在使用kotlinx-coroutines-test,您可以使用CompletableDeferred来等待。
    @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")
    }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接