调试时Android单元测试失败,否则通过

时间:2011-12-30 11:36:05

标签: android database debugging junit android-contentprovider

我有一个使用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;
}

正如我所说,测试在未处于调试模式时通过。

1 个答案:

答案 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被调用两次。

我不知道这是否有所作为......