2011-12-30 95 views
0

我有一个应用程序,它使用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; 
} 

正如我说的,测试通过当不在调试模式时。

回答

1

嗯,我想我已经知道发生了什么,即使我没有完全理解它。

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)

它并没有真正解释为什么第一次插入是成功的。它并不能解释为什么测试通过“运行”模式。我在ContentProviderSQLiteOpenHelper中添加了一些日志记录到onCreate(),在运行模式下ContentProvideronCreate()被调用两次。

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