我有一个使用sqlite数据库和ContentProvider来提供数据的应用程序。 eclipse项目有一个单元测试,它将记录添加到数据库,检索它并根据检索到的数据进行断言:
public void testAddNewVehicle()
{
Vehicle vehicle1 = new Vehicle("xyz", "my car", 111f);
long result = VehicleProvider.addVehicle(getContext(), vehicle1);
assertTrue(1 == result);
ArrayList<Vehicle> vehicles = VehicleProvider.getVehicles(getContext());
assertEquals(1, vehicles.size());
assertEquals("xyz", vehicles.get(0).getRegistrationNo());
assertEquals("my car", vehicles.get(0).getDescription());
assertEquals(111.0f, vehicles.get(0).getInitialMileage());
}
我的设置方法删除了数据库:
@Override
protected void setUp() throws Exception
{
super.setUp();
deleteTestDatabase();
}
当我选择'run'时测试通过,但如果我选择debug,它会在assertEquals(1, vehicles.size());
行失败。单步执行代码后,我注意到一些奇怪的事情:即使数据插入成功并且assertTrue(1 == result);
通过,此时数据库也不存在于文件系统上。它仅在调用VehicleProvider.getVehicles(getContext());
时创建。
addVehicle()和getVehicles()都会导致对getWritableDatabase()
的调用,所以我不明白为什么第一次调用不会在磁盘上创建数据库。 addVehicle()方法最终会调用insert()(省略不相关的代码):
@Override
public Uri insert(Uri uri, ContentValues values)
{
String table = table = Constants.VEHICLE_TABLE_NAME;
long rowID = UKMPGDataProvider.getWritableDatabase().insert(table, null, values);
// ---if added successfully---
if (rowID > 0)
{
Uri insertedRowUri = insertedRowUri = ContentUris.withAppendedId(VEHICLE_CONTENT_URI, rowID);
getContext().getContentResolver().notifyChange(insertedRowUri, null);
return insertedRowUri;
}
throw new SQLException("Failed to insert row into " + uri);
}
getVehicle()最终将调用query():
@Override
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder)
{
SQLiteQueryBuilder sqlBuilder = new SQLiteQueryBuilder();
sqlBuilder.setTables(uri.getPathSegments().get(0));
if (uriMatcher.match(uri) == VEHICLE_ID)
// ---if getting a particular vehicle
sqlBuilder.appendWhere(BaseColumns._ID + " = " + uri.getPathSegments().get(1));
if (sortOrder == null || sortOrder == "")
{
sortOrder = BaseColumns._ID;
}
Cursor c = sqlBuilder.query(UKMPGDataProvider.getWritableDatabase(), projection, selection, selectionArgs, null, null, sortOrder);
// ---register to watch a content URI for changes---
c.setNotificationUri(getContext().getContentResolver(), uri);
return c;
}
正如我所说,测试在未处于调试模式时通过。
答案 0 :(得分:1)
好吧,我想我发现了发生了什么,即使我不完全理解它。
在我onCreate()
的{{1}}中,我打开了数据库:
ContentProvider
(在我的辩护中,这是从网上的教程复制的。)
在我的测试中, @Override
public boolean onCreate()
{
UKMPGDataProvider.init(getContext(), Constants.DATABASE_NAME);
return (UKMPGDataProvider.getWritableDatabase() == null) ? false : true;
}
会在addVehicle()
上调用getWriteableDatabase()
,这看起来像这样(为了清晰起见缩短了):
SQLiteOpenHelper
当我打开数据库时,执行不会通过第一个public synchronized SQLiteDatabase getWritableDatabase() {
if (mDatabase != null && mDatabase.isOpen() && !mDatabase.isReadOnly()) {
return mDatabase; // The database is already open for business
}
//lots more initialisation here, omitted
int version = db.getVersion();
if (version != mNewVersion) {
db.beginTransaction();
try {
if (version == 0) {
//DATABASE CREATED HERE
onCreate(db);
//END
} else {
onUpgrade(db, version, mNewVersion);
}
db.setVersion(mNewVersion);
db.setTransactionSuccessful();
} finally {
db.endTransaction();
}
}
//omitted code again
}
语句,永远不会到达if
行。
在我的代码中,我会在插入车辆后关闭数据库,因此下一次调用onCreate(db)
(getVehicles())将传递第一个getWriteableDatabase()
语句并执行if
它并没有真正解释为什么第一次插入是成功的。并没有解释为什么测试在“运行”模式下通过。我在onCreate(db)
和onCreate()
的{{1}}添加了一些日志记录,在运行模式下,ContentProvider
SQLiteOpenHelper
被调用两次。
我不知道这是否有所作为......