17

AndroidアプリケーションでRobolectricを使用して単純なSQLiteデータベースをテストしようとしています。いくつかの値を入力していますが、それらを読み戻すと0行が返されます。

SQLiteOpenHelperクラスを使用してデータベースにアクセスしています。

// RequestCache extends SQLiteOpenHelper
RequestCache cache = new RequestCache(activity); 
SQLiteDatabase db = cache.getWritableDatabase();

// Write to DB
ContentValues values = new ContentValues();
values.put(REQUEST_TIMESTAMP, TEST_TIME); 
values.put(REQUEST_URL, TEST_URL);
db.insertOrThrow(TABLE_NAME, null, values);

// Read from DB and compare values      
Vector<Request> matchingRequests = new Vector<Request>();
db = cache.getReadableDatabase();
Cursor cursor = db.query(TABLE_NAME, SEARCH_URL_RETURN_COLUMNS, SEARCH_URL_WHERE, new String[] {url}, null, null, ORDER_BY, null);
int id = 0;

while(cursor.moveToNext()) {
    long timestamp = cursor.getLong(0);
    Request request = new Request(id++);
    request.setUrl(url);
    request.setCreationTimestamp(new Date(timestamp));
    matchingRequests.add(request);
}


// Assert that one row is returned
assertThat(matchingRequests.size(), equalTo(1));  // fails, size() returns 0

robolectricの外部でコードをデバッグする場合、これは期待どおりに機能します。私は何か間違ったことをしていますか、それともRobolectricを使用してSQliteデータベースをテストすることはできませんか?

4

3 に答える 3

20

Robolectric 2.3は、シャドウとフェイクのコレクションではなく、SQLiteの実際の実装を使用します。実際のデータベースの動作を検証するためのテストを作成できるようになりました。

于 2014-07-04T16:42:26.350 に答える
10

注:この回答は古くなっています。Roboletric 2.Xを使用している場合は、https: //stackoverflow.com/a/24578332/850787をご覧ください。

問題は、RobolectricのSQL​​iteDatabaseがメモリにのみ保存されるため、getReadableDatabaseまたはgetWritableDatabaseを呼び出すと、既存のデータベースが新しい空のデータベースで上書きされることです。

私は同じ問題に直面していましたが、私が見つけた唯一の解決策は、Robolectricプロジェクトをフォークし、同じコンテキストが2回与えられた場合にデータベースを保存するためにShadowSQLiteOpenHelperを追加する必要があることでした。ただし、フォークの問題は、contexが指定されたときにclose()関数を「無効にする」必要があることです。そうしないと、Connection.close()がメモリ内のデータベースを破棄するためです。プルリクエストを行いましたが、まだプロジェクトにマージされていません。

しかし、私のバージョンのクローンを作成してください。問題が解決するはずです(正しく理解していれば:P)。GitHubで見つけることができます:https ://github.com/waltsu/robolectric

変更の使用方法の例を次に示します。

Context c = new Activity(); 
SQLiteOpenHelper helper = new SQLiteOpenHelper(c, "path", null, 1); 
SQLiteDatabase db = helper.getWritableDatabase(); 
// With the db write something to the database 
db.query(...); 
SQLiteOpenHelper helper2 = new SQLiteOpenHelper(c, "path", null, 1); 
SQLitedatabase db2 = helper2.getWritableDatabase(); 
// Now db and db2 is actually the same instance 
Cursor c = db2.query(...) ; // Fetch the data which was saved before 

もちろん、新しいSQLiteOpenHelperを作成する必要はありませんが、これは、同じコンテキストを2つの異なるSQLiteOpenHelperに渡すと同じデータベースが得られることを示す単なる例です。

于 2012-02-04T16:04:02.377 に答える
2

受け入れられた回答にリンクされているコードは私には機能しませんでした。古くなっている可能性があります。あるいは、私の設定が違うだけかもしれません。Robolectric 2.4スナップショットを使用していますが、何かを見逃していない限り、ShadowSQLiteOpenHelperが含まれていないようです。いずれにせよ、私は解決策を見つけました。これが私がしたことです:

  1. ShadowSQLiteOpenHelperというクラスを作成し、上記のリンクされたコードの内容をコピーして貼り付けました(https://github.com/waltsu/robolectric/blob/de2efdca39d26c5f18a3d278957b28a555119237/src/main/java/com/xtremelabs/robolectric/shadows/ShadowSQLiteOpenHelper java)、およびインポートを修正しました。
  2. カスタムシャドウを使用するためのhttp://robolectric.org/custom-shadows/の指示に従って、テストクラスに。という注釈を付けました@Config( shadows = { ShadowSQLiteOpenHelper.class } )。カスタムテストランナーは必要ありません。
  3. 私のテストでは、SQLiteOpenHelperのサブクラスをインスタンス化new Activity()し、コンテキストとしてaを渡し(Robolectricがそれを喜んで処理します)、通常どおりに使用しました。

この時点で、実際のデータベースファイルがローカルで作成されていることに気付きました。SQLiteOpenHelperサブクラスを使用したテストを最初に実行した後、テーブルがすでに存在していたため、後続のテストでSQLiteExceptionが発生し続けました。そして、「path」というファイルと「path-journal」というファイルがローカルリポジトリにあるのを見ることができました。シャドウクラスがインメモリデータベースを使用しているという印象を受けたため、これは私を混乱させました。

シャドウクラスの問題のある行は次のとおりです。

database = SQLiteDatabase.openDatabase( "path", null, 0 );

getReadableDatabase()とgetWriteableDatabase()の両方で。実際のSQLiteOpenHelperがインメモリデータベースを作成できることを知っていたので、ソースを調べてそれがどのように行われるかを確認した後、上記の行を次のように置き換えました。

database = SQLiteDatabase.create( null );

その後、すべてが機能しているようです。行を挿入して読み戻すことができます。

うまくいけば、これは他の誰かを助けるでしょう。

この質問とは正確には関係ありませんが、誰かをさらに助けるかもしれない、私に起こった奇妙なことの1つは、私もjmockitを使用していて、同じクラスの1つのテストでそれを使用したことです。しかし、何らかの理由で、これによりカスタムシャドウクラスが使用されなくなりました。そのクラスだけをMockitoに切り替えましたが、問題なく動作します。

于 2014-07-02T08:48:47.490 に答える