Reputation: 2122
I have been developing android applications but didn't write any unit tests. Recently I started to learn about it and try to use JUnit to test my android applications.
I found that most of the times I get bugs in API calls, But I still can't understand how to write unit tests for them(& how to make the original code testable).
Let me explain the following function:
I am running a function call setOffenceList(). There are multiple actions happening inside the function.
i) Load the RestClient and pass the URL.
ii) RestClient talk to the JSON api and get the response
ii) I grab the response inside the onSuccess(String response) function
iii) Parse the JSON data and store inside an array
iv) If success I will show data in a list view (else show an error message)
This is the code:
public class OffenceFrag extends Fragment {
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.frag_offence, container, false);
//run API call
setOffenceList();
return view;
}
private void setOffenceList() {
String url = Paths.SITE_URL ;
RestClient.get(url, null, new AsyncHttpResponseHandler() {
@Override
public void onStart() {
Toast.makeText(getActivity(), "Loading offences...", Toast.LENGTH_SHORT).show();
}
@Override
public void onSuccess(String response) {
//Parse JSON
JSONArray jsonArray;
try {
JSONObject jsonObj = new JSONObject(response);
if(jsonObj.getString("status").equalsIgnoreCase("Success")){
jsonArray = new JSONArray(jsonObj.getString("data"));
if(jsonArray.length() > 0){
for (int i = 0; i < jsonArray.length(); i++) {
JSONObject row = jsonArray.getJSONObject(i);
OffenceORM off = new OffenceORM();
off.setOffenceId(row.getString("offence_id"));
off.setPhoto(row.getString("photo"));
off.setSubmittedBy(row.getString("submitted_by"));
offenceList.add(off);
}
}
//Success: Show the list view
setOffenceAdapter();
Toast.makeText(getActivity(), "Successfully Loaded", Toast.LENGTH_LONG).show();
} else {
//Failed: show error message
Toast.makeText(getActivity(), "There are no offences submitted under project", Toast.LENGTH_LONG).show();
}
} catch (Exception e) {
Log.e("exception", e.getMessage());
}
}
@Override
public void onFailure(Throwable error, String content) {
Log.e("failed", error.getMessage());
}
@Override
public void onFinish() {
}
});
}
}//end
I can't really understand how can I write a test function to something like the above code.
Can you please show me how to break down this code to testable pieces and write unit test functions to them?
Thanks a lot!
Upvotes: 6
Views: 2074
Reputation: 1053
Only and only a good design can help you making Unit testing easier. That's why Test Driven Development is there. So that you can not go with wrong design.
When you unit test you simply test code written by you and use mock objects provided by Android to test android Api calls.
As far as other Api have issues than its the issue of Api developer not yours. You can use mock framework like Mockito to test functionality of your code when it make call to other API code. Test API code separately if you are developing your own API.
Design principles must be followed for good design like
Important Points:
Unit testing a badly design code is complete wastage. As test will break every time you make some changes to classes. In Android this will happen even more. As you are stuck with Android life cycle methods.
Carefully abstract away functionality that you want to test in their own classes.
This will make your application code more robust, simple and clear.
Upvotes: 6
Reputation: 5939
The advice of Rohit Khatkar to use TDD is certainly worth considering for the next code you develop. But, now that this code exists and you are asking "how to break down this code into testable pieces": You could at first ignore testability, and just try to break down this code into smaller pieces: Exline class definitions and split up methods, just as for optimizing readability in general. You will already find some redundancy (the if around the for loop).
As an effect, each of the resulting methods will likely have less dependencies on other classes. Then, you can focus on reducing these dependencies. Check out Michael Feather's book on dealing with legacy code for a whole bunch of approaches to break dependencies. EDIT: Someone has extracted a list of dependency breaking techniques (only high level descriptions, though): http://rubyexperiences.blogspot.de/2005/12/dependency-breaking-techniques-from.html
Upvotes: 1
Reputation: 1836
You're doing too much stuff in Fragment, it's hard to test and give maintaining.
I'm using the MVP pattern in my projects, who allows separate the presentation layer from the logic, avoiding to put all the code in fragment/activity.
Check this article: http://antonioleiva.com/mvp-android/
And the respective code sample in GitHub: https://github.com/antoniolg/androidmvp
Upvotes: 1