【发布时间】:2015-10-30 16:10:33
【问题描述】:
我正在尝试在我的应用程序中实现一些测试。我想测试的一件事是将 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 的实例。
【问题讨论】:
-
你为什么使用
context.getApplicationContext()?context不应该就够了吗? -
删除 getApplicationContext() 并再次测试会导致相同的行为。
-
@MeghVidani context.getApplicationContext() 确实返回 null,所以您说这是问题之一是正确的。但是,删除 getApplicationContext() 部分后,我仍然遇到问题。
标签: android unit-testing junit