testing the display of alert when internet connectivity unavailable roboelectric android

0

I am using Roboelectric to test a simple android app. It has an activity, having a button, clicking on the button, it displays an alert message whether I am connected to internet or not. I am using ConnectivityManager and checking availability of either WiFi or Mobile network.

This is the onClick method of the button.

 netButton.setOnClickListener(new OnClickListener(){
 @Override
 public void onClick(View v) {
 if(isConnectedToInternet()){
 new AlertDialog.Builder(MainActivity.this).setMessage("You are connected to internet").setNeutralButton("OK", new DialogInterface.OnClickListener() {
     public void onClick(DialogInterface dialog, int which) {
         dialog.cancel();
     }
 }).show();
 }
 else{
 new AlertDialog.Builder(MainActivity.this).setMessage("You are not connected to internet").setNeutralButton("OK", new DialogInterface.OnClickListener() {
 public void onClick(DialogInterface dialog, int which) {
     dialog.cancel();
 }
}).show();
}
}
});

The isConnectedToInternet method is as-

public boolean isConnectedToInternet(){
connManager=(ConnectivityManager)getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo wifiNetwork =connManager.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
NetworkInfo mobileNetwork = connManager.getNetworkInfo(ConnectivityManager.TYPE_MOBILE);
if (wifiNetwork!=null && wifiNetwork.isConnected()){
return true;
else if (mobileNetwork!=null && mobileNetwork.isConnected()){
return true;
return false;
}

The app runs fine. Also, when I run it using Roboelectric, and manually set the type of connection to Mobile or WiFi to test whether alert is displayed the test and assertion runs fine. But if I set the type to any other type (let say WIMAX or to a constant which does not pertain to any type 0x0000000A), it always maps to the type Mobile (constant 0x00000000)

Below is my code to check the non-availability of internet and the display of alert message.

'MainActivityTest.java'

    public void testAlertForNonNetwork(){
    setUpActivity();

    connManager=(ConnectivityManager)Robolectric.application.getSystemService(Context.CONNECTIVITY_SERVICE);
    ShadowConnectivityManager sConnManager=Robolectric.shadowOf_(connManager);
    sConnManager.setNetworkInfo(0x0000000A,sConnManager.getActiveNetworkInfo());
    pushSecondButton();
    AlertDialog alert=ShadowAlertDialog.getLatestAlertDialog();
    assertNotNull("the alert is null",alert!=null);
    ShadowAlertDialog sAlert=shadowOf_(alert);
    assertNotNull("the salert is null",sAlert!=null);
    assertThat(sAlert.getMessage().toString(),equalTo("You are not connected to internet"));
    }

Here the setUpActivity and pushSecondButton are simple methods to set the activity and push the button.

This assertion always fails. Interesting part is if I comment the code in the MainActivity.java where the connectivity with Mobile data is checked, then my assertion runs successfully,

Does any one has idea, why does Roboelectric map any other connection to Mobile, in case I use ConnectivityManager.WIMAX instead of the constant 0x0000000A in the MainActivityTest, this behaviour is replicable.

I tried to display the value using System.out.println(xxxNetwork.getType()), and any type other than WiFi and Mobile maps to Mobile, the constant 0.

android
eclipse
junit4
robolectric
asked on Stack Overflow Sep 11, 2014 by inquisitive • edited Sep 11, 2014 by inquisitive

2 Answers

1

I can't recreate the error you mention of the wrong thing returning type mobile. Arbitrary types, including TYPE_WIMAX and the int 35, return null when I query the ShadowConnectivityManager. This is the behavior I expect, which is comforting.

As to why your test is failing, I believe this is due to the fact that by default Robolectric adds a TYPE_WIFI and TYPE_MOBILE NetworkInfo. See the source. The default says mobile is connected and wifi is disconnected. I'm not sure why this is. Here is the pertinent code:

  public ShadowConnectivityManager() {
    NetworkInfo wifi = ShadowNetworkInfo.newInstance(NetworkInfo.DetailedState.DISCONNECTED, ConnectivityManager.TYPE_WIFI, 0, true, false);
    networkTypeToNetworkInfo.put(ConnectivityManager.TYPE_WIFI, wifi);

    NetworkInfo mobile = ShadowNetworkInfo.newInstance(NetworkInfo.DetailedState.CONNECTED, ConnectivityManager.TYPE_MOBILE, ConnectivityManager.TYPE_MOBILE_MMS, true, true);
    networkTypeToNetworkInfo.put(ConnectivityManager.TYPE_MOBILE, mobile);

    this.activeNetwork = mobile;
  }

In your test I would first set the NetworkInfo that I expect. In your case, this would be setting both wifi and mobile to be disconnected.

I would also recommend using the named ints rather than their raw values, e.g. TYPE_WIMAX rather than 0x0000000A or whichever constant that maps to. This will make it easier to read and maintain.

EDIT:

Out of space in the comments. To fix the tests, I would start by ensuring that at the beginning of each test your system is in a known state. You were trying to do this, it looks like, but were thwarted by the fact that robolectric plops in those defaults. So in your @Before method (or setUp() or whatever the @Before analogue is if you're using JUnit 3), I would get set the mobile value to disconnected. You can also do this on a per-test basis, of course--whatever makes the most sense.

Here in my @Before method I use the ShadowConnectivityManager to say that mobile is disconnected, and then I assert that this is indeed the case in the single test. I've never used this in my own tests, so you might have to fiddle a bit to make sure all the parameters to newInstance() are correct. For example I don't know off the top of my head which gets precedence--the first parameter or the final one, so if you said DetailedState.CONNECTED and the last parameter false I don't know what isConnected() would return.

I can vouch for the fact that on my current setup this tests passes, and fails if I remove the call to setNetworkInfo().

You might also want to move the ConnectivityManager object to a class field to keep things clean, which it looks like you've already done in your code. Make sure to reset any necessary state between tests if you go this route, of course.

  @Before
  public void before() {

    ConnectivityManager cm = (ConnectivityManager)
        Robolectric.application.getSystemService(Context.CONNECTIVITY_SERVICE);

    ShadowConnectivityManager shadowCM = Robolectric.shadowOf(cm);

    shadowCM.setNetworkInfo(
        ConnectivityManager.TYPE_MOBILE,
        ShadowNetworkInfo.newInstance(
            DetailedState.DISCONNECTED,
            ConnectivityManager.TYPE_MOBILE,
            ConnectivityManager.TYPE_MOBILE_MMS,
            true,
            false));


  }

  @Test
  public void mobileIsDisconnected() {
    ConnectivityManager cm = (ConnectivityManager)
        Robolectric.application.getSystemService(Context.CONNECTIVITY_SERVICE);

    NetworkInfo mobileInfo =
        cm.getNetworkInfo(ConnectivityManager.TYPE_MOBILE);

    assertThat(mobileInfo.isConnected()).isFalse();
  }
answered on Stack Overflow Sep 20, 2014 by user1978019 • edited Sep 22, 2014 by user1978019
0
    if (hasConnection()) {

//write your code
}
else{
Open_dilog();
}


//Method of Open_dilog()


private void Open_dilog() {
        // TODO Auto-generated method stub

        AlertDialog.Builder builder = new AlertDialog.Builder(
                Sharing_activity.this);
        builder.setTitle("Title name");
        builder.setMessage("No Internet Connection Available.");
        builder.setPositiveButton("OK", new DialogInterface.OnClickListener() {

            @Override
            public void onClick(DialogInterface dialog, int which) {
                // TODO Auto-generated method stub
                dialog.dismiss();

            }
        });
        AlertDialog dialog_show = builder.create();
        dialog_show.show();

    }

public static boolean hasConnection() { ConnectivityManager cm = (ConnectivityManager) this.getContext().getSystemService( Context.CONNECTIVITY_SERVICE);

NetworkInfo wifiNetwork = cm.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
if (wifiNetwork != null && wifiNetwork.isConnected()) {
  return true;
}

NetworkInfo mobileNetwork = cm.getNetworkInfo(ConnectivityManager.TYPE_MOBILE);
if (mobileNetwork != null && mobileNetwork.isConnected()) {
  return true;
}

NetworkInfo activeNetwork = cm.getActiveNetworkInfo();
if (activeNetwork != null && activeNetwork.isConnected()) {
  return true;
}

return false;

}

answered on Stack Overflow Sep 11, 2014 by Ramesh Devaiya • edited Sep 11, 2014 by Ramesh Devaiya

User contributions licensed under CC BY-SA 3.0