JUnit testing - Best and most reliable way to do my tests?

560 Views Asked by At

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?

2

There are 2 best solutions below

0
On

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.

2
On

Unit-Test is low-level testing without an database or an external server. What you search for is a integration-test or even click-tests.