vendredi 30 octobre 2015

Android NPE running JUnit test

I'm trying to implement some tests in my application. One thing that I want to test is writing a java object to my db, then retrieving it and asserting the the object that comes out of the db matches the object that went in.

Here's my MySQLiteHelper application code:

import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import java.util.concurrent.atomic.AtomicInteger;

class MySQLiteHelper extends SQLiteOpenHelper {

    private static final String DATABASE_NAME = "unittesttester.db";
    private static final int DATABASE_VERSION = 8;
    private static final String LOG_TAG = MySQLiteHelper.class.getSimpleName();

    private static final int WEATHER_STALENESS_PERIOD_MS = 60 * 5 * 1000; //5 minutes

    private AtomicInteger mOpenCounter = new AtomicInteger();
    private static MySQLiteHelper mInstance = null;
    private SQLiteDatabase db;
    private Context mContext;

    public static MySQLiteHelper getInstance(Context context) {
        if (mInstance == null) {
            mInstance = new MySQLiteHelper(context.getApplicationContext());
        }

        return mInstance;
    }

    private MySQLiteHelper(Context context) {
        super(context, DATABASE_NAME, null, DATABASE_VERSION);
        mContext = context;
    }

    @Override
    public void onCreate(SQLiteDatabase db) {
        db.execSQL(WeatherTable.CREATE_TABLE_WEATHER);
    }

    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
        if (newVersion <= DATABASE_VERSION) {
            onCreate(db);
        }
    }

    private synchronized SQLiteDatabase openDatabase() {
        final int i = mOpenCounter.incrementAndGet();
        if (i == 1) {
            db = getWritableDatabase();
        }
        return db;
    }

    private synchronized void closeDatabase() {
        final int i = mOpenCounter.decrementAndGet();
        if (i == 0) {
            db.close();
        }
    }

    private void truncateWeatherTable() {
        db = openDatabase();
        db.delete(WeatherTable.TABLE_WEATHER, null, null);
        closeDatabase();
    }


    public void deleteAndInsertWeather(Weather weather) {
        db = openDatabase();
        db.beginTransaction();
        try {
            truncateWeatherTable();
            insertWeather(weather);
            db.setTransactionSuccessful();
        } finally {
            db.endTransaction();
            closeDatabase();
        }
    }

    private void insertWeather(Weather weather) {
        db = openDatabase();
        db.insert(WeatherTable.TABLE_WEATHER, null, makeWeatherCv(weather));
        closeDatabase();
    }

    public Weather getWeather() {
        db = openDatabase();
        String sql = "SELECT * FROM " + WeatherTable.TABLE_WEATHER;
        Cursor c = null;
        Weather weather = null;
        try {
            c = db.rawQuery(sql, null);
            if (c.moveToFirst()) {
                weather = makeWeather(c);
                //If sample too old return null
                if (System.currentTimeMillis() - weather.getTimestamp() > WEATHER_STALENESS_PERIOD_MS) {
                    weather = null;
                    truncateWeatherTable();
                }
            }
        } finally {
            if (c != null) {
                c.close();
            }
            closeDatabase();
        }
        return weather;
    }


    private Weather makeWeather(Cursor c) {
        Weather weather = new Weather();
        weather.setTimestamp(c.getLong(c.getColumnIndex(WeatherTable.COLUMN_TIMESTAMP)));
        weather.setElevation(c.getDouble(c.getColumnIndex(WeatherTable.COLUMN_ELEVATION)));
        weather.setTemperature(c.getDouble(c.getColumnIndex(WeatherTable.COLUMN_TEMPERATURE)));
        weather.setDusk(c.getInt(c.getColumnIndex(WeatherTable.COLUMN_DUSK)));
        weather.setNighttime(c.getInt(c.getColumnIndex(WeatherTable.COLUMN_NIGHTTIME)));
        weather.setGravity(c.getDouble(c.getColumnIndex(WeatherTable.COLUMN_GRAVITY)));
        weather.setDaytime(c.getInt(c.getColumnIndex(WeatherTable.COLUMN_DAYTIME)));
        weather.setHumidity(c.getDouble(c.getColumnIndex(WeatherTable.COLUMN_HUMIDITY)));
        weather.setPressure(c.getDouble(c.getColumnIndex(WeatherTable.COLUMN_PRESSURE)));
        weather.setOkta(c.getDouble(c.getColumnIndex(WeatherTable.COLUMN_OKTA)));
        weather.setDawn(c.getInt(c.getColumnIndex(WeatherTable.COLUMN_DAWN)));
        return weather;
    }

    private ContentValues makeWeatherCv(Weather weather) {
        ContentValues contentValues = new ContentValues();
        contentValues.put(WeatherTable.COLUMN_TIMESTAMP, weather.getTimestamp());
        contentValues.put(WeatherTable.COLUMN_TEMPERATURE, weather.getElevation());
        contentValues.put(WeatherTable.COLUMN_TEMPERATURE, weather.getTemperature());
        contentValues.put(WeatherTable.COLUMN_DUSK, weather.getDusk());
        contentValues.put(WeatherTable.COLUMN_NIGHTTIME, weather.getNighttime());
        contentValues.put(WeatherTable.COLUMN_GRAVITY, weather.getGravity());
        contentValues.put(WeatherTable.COLUMN_DAYTIME, weather.getDaytime());
        contentValues.put(WeatherTable.COLUMN_HUMIDITY, weather.getHumidity());
        contentValues.put(WeatherTable.COLUMN_PRESSURE, weather.getPressure());
        contentValues.put(WeatherTable.COLUMN_OKTA, weather.getOkta());
        contentValues.put(WeatherTable.COLUMN_DAWN, weather.getDawn());
        return contentValues;
    }
}

Here's my test class for the class above:

import android.test.AndroidTestCase;
import android.test.RenamingDelegatingContext;

import org.junit.Test;
import static org.mockito.Mockito.*;

public class MySQLiteHelperTest extends AndroidTestCase {

    private MySQLiteHelper db;
    private Weather mockedWeather = mock(Weather.class);

    @Override
    public void setUp() throws Exception {
        super.setUp();
        RenamingDelegatingContext context = new RenamingDelegatingContext(getContext(), "test_");
        db = MySQLiteHelper.getInstance(context);

        when(mockedWeather.getDawn()).thenReturn(0);
        when(mockedWeather.getDaytime()).thenReturn(1);
        when(mockedWeather.getDusk()).thenReturn(2);
        when(mockedWeather.getElevation()).thenReturn(3.0);
        when(mockedWeather.getGravity()).thenReturn(4.0);
        when(mockedWeather.getHumidity()).thenReturn(5.0);
        when(mockedWeather.getNighttime()).thenReturn(6);
        when(mockedWeather.getOkta()).thenReturn(7.0);
        when(mockedWeather.getPressure()).thenReturn(8.0);
        when(mockedWeather.getTemperature()).thenReturn(9.0);
        when(mockedWeather.getTimestamp()).thenReturn(10L);
    }

    @Override
    public void tearDown() throws Exception {
        super.tearDown();
    }

    public void testGetInstance() throws Exception {

    }

    public void testOnCreate() throws Exception {

    }

    public void testOnUpgrade() throws Exception {

    }

    @Test
    public void testDeleteAndInsertWeather() throws Exception {
        db.deleteAndInsertWeather(mockedWeather);
        Weather actualWeather = db.getWeather();
        assertEquals(mockedWeather.getDawn(), actualWeather.getDawn());
        assertEquals(mockedWeather.getDaytime(), actualWeather.getDaytime());
        assertEquals(mockedWeather.getDusk(), actualWeather.getDusk());
        assertEquals(mockedWeather.getElevation(), actualWeather.getElevation());
        assertEquals(mockedWeather.getGravity(), actualWeather.getGravity());
        assertEquals(mockedWeather.getHumidity(), actualWeather.getHumidity());
        assertEquals(mockedWeather.getNighttime(), actualWeather.getNighttime());
        assertEquals(mockedWeather.getOkta(), actualWeather.getOkta());
        assertEquals(mockedWeather.getPressure(), actualWeather.getPressure());
        assertEquals(mockedWeather.getTemperature(), actualWeather.getTemperature());
        assertEquals(mockedWeather.getTimestamp(), actualWeather.getTimestamp());

    }

    public void testDeleteWeather() throws Exception {

    }

    public void testInsertWeather() throws Exception {

    }

    public void testGetWeather() throws Exception {

    }

    public void testWeatherMakeCv() throws Exception {

    }
}

When I run the test I am getting a NPE during my test. It seems to occur when the MySQLiteHelper class has its db = getWritableDatabase() line. getWriteableDatabase() is a public method from the base class.

I don't think I understand why this test results in an NPE. In my test I call the static method, MySQLiteHelper.getInstance(Context context) which should initialize the class. It is my assumption that calling getInstance will provide me with a fully initialized instance of MySQLiteHelper. Why does this not seem to be happening?

Aucun commentaire:

Enregistrer un commentaire