Android单元测试在调试中失败,否则通过
我有一个应用程序,它使用sqlite数据库和ContentProvider来提供数据。 Eclipse项目有一个单元测试,其将记录添加到数据库中,检索它并断言针对所检索的数据:Android单元测试在调试中失败,否则通过
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();
}
测试通过时,我选择“运行”,但如果我选择调试,则在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()最终会调用查询():
@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;
}
正如我说的,测试通过当不在调试模式时。
嗯,我想我已经知道发生了什么,即使我没有完全理解它。
在onCreate()
在我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)
行永远不会到达。
在我的代码,我会插入车辆后,要关闭数据库,所以下次调用getWriteableDatabase()
(getVehicles())将获得通过的第一if
语句并执行onCreate(db)
。
它并没有真正解释为什么第一次插入是成功的。它并不能解释为什么测试通过“运行”模式。我在ContentProvider
和SQLiteOpenHelper
中添加了一些日志记录到onCreate()
,在运行模式下ContentProvider
onCreate()
被调用两次。
我不知道这是否有所作为...