簡體   English   中英

運行 JUnit 測試的 Android NPE

[英]Android NPE running JUnit test

我正在嘗試在我的應用程序中實施一些測試。 我想測試的一件事是將一個 java 對象寫入我的數據庫,然后檢索它並斷言從數據庫中出來的對象與進入的對象相匹配。

這是我的 MySQLiteHelper 應用程序代碼:

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;
    }
}

這是我對上述課程的測試課程:

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();
        context = new MockContext();
        setContext(context);
        assertNotNull(context);
        RenamingDelegatingContext renamingContext = new      RenamingDelegatingContext(getContext(), "test_");
        db = MySQLiteHelper.getInstance(renamingContext);
        assertNotNull(db);

        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 {

    }
}

當我運行測試時,我在測試期間獲得了 NPE。 當 MySQLiteHelper 類有它的 db = getWritableDatabase() 行時,似乎會發生這種情況。 getWriteableDatabase() 是來自基類的公共方法。

我想我不明白為什么這個測試會導致 NPE。 在我的測試中,我調用靜態方法 MySQLiteHelper.getInstance(Context context) 來初始化類。 我假設調用 getInstance 將為我提供一個完全初始化的 MySQLiteHelper 實例。 為什么這似乎沒有發生?

編輯:我現在遇到的問題是,當調用 getWritableDatabase() 時,它返回 null 而不是 SQLiteDatabase 的實例。

我完成了對我的 sqlite 數據庫進行單元測試的目標。 問題似乎是我需要使用名為 Android Instrumentation Test 的構建工件而不是單元測試構建工件。

我在我的 app/src/androidTest/java 目錄中設置了一個測試類。 測試類擴展了 InstrumentationTestCase。

當我設置我的數據庫時,我使用 getInstrumentation().getTargetContext() 提供的上下文。 這很重要,因為最初我嘗試使用 getInstrumentation().getContext() 並且我發現這總是會導致 SQLiteCantOpenDatabaseException。

所以我的問題似乎是因為:1)我沒有使用正確的測試工件 2)我沒有使用正確的測試基類 3)我沒有正確地獲取上下文

AndroidTestCase#getContext()返回您使用setContext()設置的任何Context並且您沒有設置任何內容,因此返回null

使用SQLiteOpenHelpernull上下文將在數據庫打開時 NPE,例如使用getWritableDatabase()

有關如何在測試用例中設置 Contex 的更多詳細信息,請參閱在 AndroidTestCase 或 Android Studio 的單元測試功能中的 InstrumentationTestCase 中獲取上下文

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM