Модульный тест Android не проходит в отладке, проходит в противном случае - PullRequest
0 голосов
/ 30 декабря 2011

У меня есть приложение, которое использует базу данных 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();
}

тестирование проходит, когда я выбираю 'запустить', но если я выбираю отладку, он завершается неудачно в строке 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 Ответ

1 голос
/ 31 декабря 2011

Ну, я думаю, что узнал, что происходит, даже если я не до конца понимаю.

В 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).

Это действительно не объясняет, почему первая вставка прошла успешно. И это не объясняет, почему тест прошел в режиме «Выполнить». Я добавил некоторые записи в onCreate() в моих ContentProvider и SQLiteOpenHelper, а в режиме запуска ContentProvider onCreate() вызывается дважды.

Я не знаю, если это имело значение или нет ...

...