运行JUnit测试的Android NPE

运行JUnit测试的Android NPE,android,unit-testing,junit,Android,Unit Testing,Junit,我正在尝试在我的应用程序中实现一些测试。我想测试的一件事是将java对象写入我的数据库,然后检索它并断言数据库中的对象与进入的对象匹配 以下是我的MySQLiteHelper应用程序代码: import android.content.ContentValues; import android.content.Context; import android.database.Cursor; import android.database.sqlite.SQLiteDatabase; import

我正在尝试在我的应用程序中实现一些测试。我想测试的一件事是将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;
    }
}
当我运行测试时,我在测试期间得到了NPE。当MySQLiteHelper类有其db=getWritableDatabase()行时,似乎会发生这种情况。getWriteableDatabase()是基类中的公共方法

我想我不明白为什么这个测试会导致NPE。在我的测试中,我调用静态方法MySQLiteHelper.getInstance(上下文),它应该初始化类。我假设调用getInstance将为我提供一个完全初始化的MySQLiteHelper实例。为什么这似乎没有发生

编辑: 我现在遇到的问题是,当调用getWritableDatabase()时,它返回null而不是SQLiteDatabase的实例。

AndroidTestCase\getContext()
返回您使用
setContext()
设置的任何
上下文,而您没有设置任何内容,因此返回
null

当打开数据库时,将
null
上下文与
SQLiteOpenHelper
一起使用,例如使用
getWritableDatabase()
将NPE


有关如何在测试用例中设置上下文的更多详细信息,请参阅。

我完成了对sqlite数据库进行单元测试的目标。问题似乎是我需要使用名为Android Instrumentation Test的构建工件,而不是单元测试构建工件

我在app/src/androidTest/java目录中设置了一个测试类。测试类扩展了InstrumentationTestCase

设置数据库时,我使用getInstrumentation()提供的上下文。getTargetContext()。这一点很重要,因为最初我尝试使用getInstrumentation().getContext(),我发现这总是会导致SQLiteCantoPendDatabaseException

所以我的问题似乎是因为: 1) 我没有使用正确的测试工件 2) 我没有使用正确的测试基类
3) 我没有正确获取上下文

为什么要使用
context.getApplicationContext()
context
不应该只满足要求吗?删除getApplicationContext()并再次测试会导致相同的行为。@MeghVidani context.getApplicationContext()会返回null,因此您可以确定这是问题之一。但是,在删除getApplicationContext()部分后,我仍然有问题;setContext(context);assertNotNull(上下文);RenamingDelegatingContext renamingContext=新的RenamingDelegatingContext(getContext(),“test”);db=MySQLiteHelper.getInstance(重命名上下文);assertNotNull(db);现在我在代码后面得到一个NPE。现在,当我调用db.beginTransaction()时就会出现这种情况;在正在测试的方法中。
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 {

    }
}