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
.
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();
}
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;
}
User contributions licensed under CC BY-SA 3.0