Android asynctask and mockito (or powre mockito)
I have a configuration manager that can retrieve JSON from the remote server, parse it into a configwrapper object, and return the object as a parameter in the provided callback listener
Therefore, in the test course, I call it:
@Test
public void init_Configuration_With_Network_Load_JSON_From_Server_Return_To_Listener() {
mockConnectivityCheck(true);
...
mManager.initConfiguration(mContext, eq(anyString()), mListener);
verify(mListener, times(1)).onConfigurationLoaded(any(ConfigWrapper.class));
}
Mcontext and mlistener are simulated. This will call the method of the tested class:
public void initConfiguration(Context context, String url, ConfigurationManagerListener listener){
// Get a reference to shared preferences
mSharedPref = context.getSharedPreferences(PREF_FILE, Context.MODE_PRIVATE);
// If we have network, we should load configurations from remote, otherwise, try to load it from assets folder OR shared pref
if (NetworkTools.hasNetworkConnection(context)){
getConfigurationRemote(context, url, listener);
} else {
getConfigurationOffline(context, listener);
}
}
Therefore, if we have a network, we can get the configuration from the server. This method does the following:
private void getConfigurationRemote(final Context context, String url, final ConfigurationManagerListener
listener) {
// Send a request to get the configuration
new AsyncTask<String, Void, HashMap<String, Object>> () {
@Override
protected HashMap<String, Object> doInBackground(String... params) {
InputStream in = null;
HashMap result = null;
try {
URL url = new URL(params[0]);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setReadTimeout(10000 /* milliseconds */);
conn.setConnectTimeout(10000 /* milliseconds */);
conn.setRequestMethod("GET");
conn.setDoInput(true);
conn.connect();
in = conn.getInputStream();
result = new ObjectMapper().readValue(in, HashMap.class);
in.close();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (in != null){
in.close();
}
} catch (IOException e) {
e.printStackTrace();
}
return result;
}
}
@Override
protected void onPostExecute(HashMap<String, Object> config) {
// We if have a valid result, save the data to shared pref AND save it to a ConfigurationWrapper object
// other wise, try to load from assets folder or shared pref if available
if (config != null && config.size() > 0){
// We want to save the hierarchy of the JSON so we save its string representation to shared pref
JSONObject object = new JSONObject(config);
mSharedPref.edit().putString(CONfigURATIONS_KEY, object.toString()).apply();
mConfigurationWrapper = new ConfigWrapper(config);
listener.onConfigurationLoaded(mConfigurationWrapper);
} else {
// No valid configuration from Remote Server, so load it from local source
getConfigurationOffline(context, listener);
}
}
}.execute(url);
}
Now, I'm trying to write a unit test that can test this code using mockito (or powermockito, if necessary). I'm not completely sure how to solve this situation. In this case, I'll call the method with the new asynctask(). Execute(). So far, after calling execute(), Will stop calling the initconfiguration method and simulate a network check to return true. Doinbackground() does not appear to have been called
How would you test such code? thank you!
resolvent:
The way the code is set up makes unit testing difficult. I suggest rescheduling it
The getconfigurationremote method currently performs three separate operations:
>Create asynctask > define the role of the task > execute task
My solution:
>Move the anonymous asynctask to its own class. > move the creation of the task (New asynctask (...) to the factory class, or preferably use a dependency injection framework such as dagger
This is what I finally imagined:
private void getConfigurationRemote(final Context context, String url, final ConfigurationManagerListener listener) {
// create the task
ConfigurationRemoteAsyncTask task = taskFactory.createConfigurationRemoteTask(listener);
// Send a request to get the configuration
task.execute(url);
}
Now you can simulate and test more easily:
>By simply simulating the task returned by the task factory, verify whether task.execute is called with the given URL when calling. Initconfiguration. > verify whether listener.onconfigurationloaded is called when calling task.onpostexecute without simulating the entire network infrastructure. It may look like this:
@Test
public void init_Configuration_With_Network_Load_JSON_From_Server_Return_To_Listener() {
ConfigurationRemoteAsyncTask task = new ConfigurationRemoteAsyncTask(mockedListener);
HashMap<String, Object> config = getNotEmptyConfig();
task.onPostExecute(config);
verify(mockedListener).onConfigurationLoaded(any(ConfigWrapper.class));
}