I'm testing my android app using JUnit
. It's the first time I do JUnit
testing for real so I don't know the path I should follow. Right now I'm testing the queries to the contacts list. Many methods just require a Raw Contact ID
or a Contact ID
as a parameter and most of them either return a JSON Object
, JSON Array
or an ArrayList
.
My question is, how should I compare my expected result with the actual result?
Right now I'm testing them like this:
public void testGetRelationship() {
JSONArray jsonArrayActual = new JSONArray();
JSONArray jsonArrayExpected = new JSONArray();
try {
jsonArrayExpected = contact.getRelationship(RAW_CONTACT_ID);
} catch (JSONException e) {
e.printStackTrace();
fail("Failed when calling the getRelationship method. " + e.getMessage());
}
Cursor cursor = getContext().getContentResolver().query(Data.CONTENT_URI,
new String[]{Relation.NAME, Relation.TYPE, Relation._ID, Relation.LABEL},
Relation.RAW_CONTACT_ID + "=? AND " + Data.MIMETYPE + "=?",
new String[]{RAW_CONTACT_ID, Relation.CONTENT_ITEM_TYPE},
null);
if(cursor.moveToFirst())
{
do{
try {
final JSONObject jsonRelationshipObject = new JSONObject();
final String name = cursor.getString(0);
final Integer type = cursor.getInt(1);
final Integer id = cursor.getInt(2);
final String label = cursor.getString(3);
jsonRelationshipObject.put("id", id);
jsonRelationshipObject.put("type", type);
jsonRelationshipObject.put("label", label);
jsonRelationshipObject.put("name", name);
jsonArrayActual.put(jsonRelationshipObject);
} catch (JSONException e) {
e.printStackTrace();
fail("Failed while adding the values to the JSONObject. " + e.getMessage());
}
} while(cursor.moveToNext());
}
else
{
cursor.close();
fail("RawContact not found! ID: " + RAW_CONTACT_ID);
}
cursor.close();
try {
JSONAssert.assertEquals(jsonArrayExpected, jsonArrayActual, true);
} catch (JSONException e) {
e.printStackTrace();
cursor.close();
fail("JSONAssert exception: " + e.getMessage());
}
}
Basically I'm calling my real method and pretty much re-coding my (under test) method. I find this unproductive or at least quite boring and tedious (coding again what I just coded sometime ago). I'm quite sure there is a better way to perform JUnit
tests. I thought about myself querying the contact list database and hand build my object to compare, something like this:
public void testGetRelationship() {
JSONArray jsonArrayActual = new JSONArray();
JSONArray jsonArrayExpected = new JSONArray();
try {
jsonArrayExpected = contact.getRelationship(RAW_CONTACT_ID);
} catch (JSONException e) {
e.printStackTrace();
fail("Failed when calling the getRelationship method. " + e.getMessage());
}
jsonRelationshipObject.put("id", 6);
jsonRelationshipObject.put("type", 1);
jsonRelationshipObject.put("label", "A label");
jsonRelationshipObject.put("name", "the name");
jsonArrayActual.put(jsonRelationshipObject);
try {
JSONAssert.assertEquals(jsonArrayExpected, jsonArrayActual, true);
} catch (JSONException e) {
e.printStackTrace();
cursor.close();
fail("JSONAssert exception: " + e.getMessage());
}
}
It is faster to code but the drawn back is I need to manually download the database from the phone (not a big deal for me) and manually query it to get the data in there (not a big deal as well) but it is not so generic, if the database changes I guess all the tests will fail. But I can get a snapshot of the database and save it and then always perform the tests on that snapshot.
Any suggestions? Improvements?
You should have a look to Mockito : https://code.google.com/p/mockito/
Basically, you have to mock your datasource / service interface cursor / content resolver and implement it with hard-coded values (some samples of your database snapshot). But this should be done only if you have to maintain the query mechanism; if this is out of scope of your project and/or don't have hands on, this would not be helpful.
For your testGetRelationship, this is more about integration testing : you inject some data on one side of your pipe and expect the same data on the other side.
In that case, JUnit is maybe not the right tool ; JMeter should be better for those needs. Here is an example of using JMeter testing JSON data : Jmeter extracting fields/parsing JSON response
Add your 'integration test' connecting a real data source in your SDLC, but those should not run every source build/development cycle. You should only run 'integration tests' at deployement time to check end-to-end integration.