Friday, August 05, 2011

Android Application Testing Guide: Q&A


Q:Diego, if we were to test something that is asynchronous, like in my case I'm wanting to test if a webview loads an URL how would I go about waiting for the webpage to finish loading in my webview ?
Posted by Pedro Veloso.

A:Actually this is a very interesting question as there are many ways and you should be cautious about WebView semantics and how some of the WebViewClient methods are called.

For example onPageFinished may be invoked wether the page was successfully loaded or there was an error. So, you may need a different approach if your intention is to test if an url was successfully loaded.

In this code snippet I'm using a MockWebViewClient to detect error conditions and simply waiting some time for the page to load. We could also iterate over a period of time checking if the value has changed instead of just waiting but we are keeping this as simple as possible. This is also assuming you have an Activity holding the WebView and it has the required getters.


/**
 * 
 */
package com.example.aatg.webview.test;

import android.test.ActivityInstrumentationTestCase2;
import android.test.suitebuilder.annotation.Suppress;
import android.webkit.WebView;
import android.webkit.WebViewClient;

import com.example.aatg.webview.AndroidHelloWebViewActivity;

/**
 * @author diego
 *
 */
public class AndroidHelloWebViewActivityTests extends
        ActivityInstrumentationTestCase2<AndroidHelloWebViewActivity> {

    private static final String VALID_URL = "http://developer.android.com";
    private static final String INVALID_URL = "http://invalid.url.doesnotexist987.com";

    private static final long TIMEOUT = 5000;

    private AndroidHelloWebViewActivity mActivity;
    private WebView mWebView;
    private MockWebViewClient mMockWebViewClient;

    /**
     * @param name
     */
    public AndroidHelloWebViewActivityTests() {
        super(AndroidHelloWebViewActivity.class);
    }

    /* (non-Javadoc)
     * @see android.test.ActivityInstrumentationTestCase2#setUp()
     */
    protected void setUp() throws Exception {
        super.setUp();
        mActivity = getActivity();
        mWebView = mActivity.getWebView();
        mMockWebViewClient = new MockWebViewClient();
        mWebView.setWebViewClient(mMockWebViewClient);
    }

    /* (non-Javadoc)
     * @see android.test.ActivityInstrumentationTestCase2#tearDown()
     */
    protected void tearDown() throws Exception {
        super.tearDown();
    }

    public final void testLoadValidUrl() {
        assertLoadUrl(VALID_URL);
        assertFalse(mMockWebViewClient.mError);
    }

    public final void testLoadInvalidUrl() {
        assertLoadUrl(INVALID_URL);
        assertTrue(mMockWebViewClient.mError);
    }

    private void assertLoadUrl(String url) {
        mWebView.loadUrl(url);
        sleep();
        assertTrue(!(mWebView.getProgress() < 100));
    }

    private void sleep() {
        try {
            Thread.sleep(TIMEOUT);
        } catch (InterruptedException e) {
            fail("Unexpected timeout");
        }
    }

    private class MockWebViewClient extends WebViewClient {
        boolean mError;

        @Override
        public void onReceivedError(WebView view, int errorCode,
                String description, String failingUrl) {
            mError = true;
        }
    }
}


Hope this helps.
Post a Comment