I want to know best practices for writing unit tests that check network connection related functions.
I have a network utility class that does four functions
- checks if network is available
- checks if device is connected
- checks if the connection is wifi
- checks if the connection is mobile data
Here are the functions in my Network utility class.
public static boolean isNetworkAvailable(@NonNull Context context) {
//check general connectivity
ConnectivityManager conMgr = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
if (conMgr != null) {
// active connection
return conMgr.getActiveNetworkInfo() != null && conMgr.getActiveNetworkInfo().isConnected();
}
// no connection
return false;
}
public static boolean isConnected(@NonNull Context context) {
ConnectivityManager conMgr = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
if (conMgr != null) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
NetworkCapabilities capabilities = conMgr.getNetworkCapabilities(conMgr.getActiveNetwork());
return capabilities != null && (capabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI) ||
capabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR));
} else {
NetworkInfo info = conMgr.getNetworkInfo(conMgr.getActiveNetwork());
return (info != null && info.isConnected());
}
}
return false;
}
public static boolean isConnectedWifi(@NonNull Context context) {
ConnectivityManager conMgr = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
if (conMgr != null) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
NetworkCapabilities capabilities = conMgr.getNetworkCapabilities(conMgr.getActiveNetwork());
return capabilities != null && (capabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI));
} else {
NetworkInfo info = conMgr.getNetworkInfo(conMgr.getActiveNetwork());
return (info != null && info.isConnected() && info.getType() == ConnectivityManager.TYPE_WIFI);
}
}
return false;
}
public static boolean isConnectedMobile(@NonNull Context context) {
ConnectivityManager conMgr = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
if (conMgr != null) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
NetworkCapabilities capabilities = conMgr.getNetworkCapabilities(conMgr.getActiveNetwork());
return capabilities != null && (capabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR));
} else {
NetworkInfo info = conMgr.getNetworkInfo(conMgr.getActiveNetwork());
return (info != null && info.isConnected() && info.getType() == ConnectivityManager.TYPE_MOBILE);
}
}
return false;
}
I would like to write unit tests for these functions but am having a difficult time manipulating the network connection to yield the various results (scenarios) I want to test. So far, I have come up with two tests for checking if wifi is still enabled after I disable and disconnect the wifi. Similarly, checking if mobile data is enabled after I have disabled it.
@Test
public void isWifiEnabled() {
WifiManager wifiManager = (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE);
wifiManager.setWifiEnabled(false);
wifiManager.disconnect();
assertFalse(NetworkUtils.isConnectedWifi(mContext));
}
@Test
public void isDataPlanEnabled() {
setMobileDataEnabled(mContext, false);
assertFalse(NetworkUtils.isConnectedMobile(mContext));
}
private void setMobileDataEnabled(Context context, boolean enabled) {
final ConnectivityManager conman = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
final Class conmanClass;
try {
conmanClass = Class.forName(conman.getClass().getName());
final Field iConnectivityManagerField = conmanClass.getDeclaredField("mService");
iConnectivityManagerField.setAccessible(true);
final Object iConnectivityManager = iConnectivityManagerField.get(conman);
final Class iConnectivityManagerClass = Class.forName(iConnectivityManager.getClass().getName());
final Method setMobileDataEnabledMethod = iConnectivityManagerClass.getDeclaredMethod("setMobileDataEnabled", Boolean.TYPE);
setMobileDataEnabledMethod.setAccessible(true);
setMobileDataEnabledMethod.invoke(iConnectivityManager, enabled);
} catch (Exception e) {
e.printStackTrace();
}
}
How can I test if network is available? I was thinking about programmatically enabling airplane mode, however, that has been disabled since 4.2.
Some device settings defined by Settings.System are now read-only. If your app attempts to write changes to settings defined in Settings.System that have moved to Settings.Global, the write operation will silently fail when running on Android 4.2 and higher. Even if your value for android:targetSdkVersion and android:minSdkVersion is lower than 17, your app is not able to modify the settings that have moved to Settings.Global when running on Android 4.2 and higher.
How can I test if network is available and force enabled/disabled states for unit tests? Or should I ignore unit tests for these functions?