Subby Subby - 1 month ago 23
Android Question

Instrumentation Testing WebView

I wish to simply construct a custom

WebView
in my
InstrumentationTest
and then check if the correct initialisation has been done.

My custom
WebView
:

public class InteractiveWebView extends WebView
{
public InteractiveWebView(final Context context)
{
super(context);
initialise(context);
}

public InteractiveWebView(final Context context, final AttributeSet attrs)
{
super(context, attrs);
initialise(context);
}

public InteractiveWebView(final Context context, final AttributeSet attrs, final int defStyleAttr)
{
super(context, attrs, defStyleAttr);
initialise(context);
}

private void initialise(final Context context)
{
if (!isInEditMode())
{
if (Build.VERSION.SDK_INT >= 19)
{
setLayerType(View.LAYER_TYPE_HARDWARE, null);
}
else
{
setLayerType(View.LAYER_TYPE_SOFTWARE, null);
}

setScrollBarStyle(WebView.SCROLLBARS_INSIDE_OVERLAY);
setFocusable(true);
setFocusableInTouchMode(true);
requestFocus(View.FOCUS_DOWN);

WebSettings settings = getSettings();

settings.setJavaScriptEnabled(true);
settings.setCacheMode(WebSettings.LOAD_NO_CACHE);
settings.setSupportMultipleWindows(false);
settings.setDomStorageEnabled(true);
settings.setDatabaseEnabled(true);
settings.setSupportZoom(false);
settings.setUseWideViewPort(false);

String databasePath = context.getApplicationContext().getDir("database", Context.MODE_PRIVATE).getPath();
settings.setDatabasePath(databasePath);
}
}
}


The
InstrumentationTest
:

@RunWith(AndroidJUnit4.class)
@SmallTest
public class InteractiveWebViewTest
{
@Test
public void constructors()
{
Context baseContext = InstrumentationRegistry.getContext();

InteractiveWebView webView1 = new InteractiveWebView(baseContext);
InteractiveWebView webView2 = new InteractiveWebView(baseContext, null);
InteractiveWebView webView3 = new InteractiveWebView(baseContext, null, 1);
}
}


As you can see, I am at this point not asserting anything, yet.

The issue which I am facing is that when I call the first
WebView
constructor, I get the following error:

java.lang.NullPointerException: Attempt to read from field 'android.os.MessageQueue android.os.Looper.mQueue' on a null object reference
at android.os.Handler.<init>(Handler.java:229)
at android.os.Handler.<init>(Handler.java:137)
at org.chromium.base.ThreadUtils.setUiThread(ThreadUtils.java:39)
at com.android.webview.chromium.WebViewChromiumFactoryProvider.ensureChromiumStartedLocked(WebViewChromiumFactoryProvider.java:197)
at com.android.webview.chromium.WebViewChromiumFactoryProvider.startYourEngines(WebViewChromiumFactoryProvider.java:294)
at com.android.webview.chromium.WebViewChromium.init(WebViewChromium.java:218)
at android.webkit.WebView.<init>(WebView.java:606)
at android.webkit.WebView.<init>(WebView.java:542)
at android.webkit.WebView.<init>(WebView.java:525)
at android.webkit.WebView.<init>(WebView.java:512)
at android.webkit.WebView.<init>(WebView.java:502)
at android.mobileconnect.gsma.com.library.view.InteractiveWebView.<init>(InteractiveWebView.java:17)


When I click on the
InteractiveWebView
link at line 17, it takes me to the constructor within that class and points to the
super(context);
call.

I have tried many other approaches such as extending the
InstrumentationTest
to be of type
ActivityInstrumentationTestCase2
in case it's the
Context
that's coming out to be null but I still get the same error. I've googled the issue several times but can't seem to fix the issue based on what I find.

Any ideas where I'm going wrong?

Answer

Solved it by mocking the InteractiveWebView but ensuring it's being constructed within a Runnable running on the Main UI thread:

getActivity().runOnUiThread(new Runnable()
{
    @Override
    public void run()
    {
        // Given
        InteractiveWebView interactiveWebView = new InteractiveWebView(getActivity());
        ....
        ....
        ....
        ....
    }
}