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)
}
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)
}
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")
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With