RoboLectricでSQLiteデータベースをテストします
-
27-10-2019 - |
質問
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データベースをテストすることはできませんか?
解決
注:この答えは時代遅れです。ロボレトリック2.xを使用している場合は、参照してください https://stackoverflow.com/a/24578332/850787
問題は、robolectricのsqlitedatabaseがメモリにのみ保存されているため、getReadableAdaTabaseまたはgetWritabledAtabaseを呼び出すと、既存のデータベースが新しい空のデータベースでオーバーライドされます。
私は同じ問題に走っていましたが、私が見つけた唯一の解決策は、同じコンテキストが2回与えられた場合にデータベースを保存するためにShadowsQLiteOpenHelperを追加する必要があるということでした。ただし、フォークの問題は、CONTEXが指定されている場合、CONTEXが指定されている場合、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に渡すと同じデータベースが得られるという例にすぎません。
他のヒント
ロボレクトリック 2.3 影と偽物のコレクションの代わりに、SQLiteの実際の実装を使用します。これで、実際のデータベース動作を検証するためにテストを作成できるようになりました。
受け入れられた答えにリンクされているコードは、私にとってはうまくいきませんでした。それは時代遅れかもしれません。または、おそらく私のセットアップはまったく異なります。私はロボレクトリック2.4スナップショットを使用していますが、これには何かを見逃さない限り、ShadowsQliteopenhelperは含まれていないようです。いずれにせよ、私は解決策を見つけました。これが私がしたことです:
- ShadowsQLiteOpenHelperというクラスを作成し、上記のコードの内容をコピーしました(https://github.com/waltsu/robolectric/blob/de2efdca39d26c5f18a3d278957b28a555119237/src/main/java/com/xtremelabs/robolectric/shadows/shadowsqlitepenhelperperperper.java)、および輸入を修正しました。
- 指示に従ってください http://robolectric.org/custom-shadows/ カスタムシャドウを使用するために、テストクラスに注釈を付けました
@Config( shadows = { ShadowSQLiteOpenHelper.class } )
. 。カスタムテストランナーは必要ありません。 - 私のテストでは、sqliteopenhelperのサブクラスをインスタンスし、
new Activity()
コンテキスト(ロボレクトリックが喜んでそれを処理します)として、通常あたりそれを使用しました。
この時点で、実際のデータベースファイルがローカルに作成されていることに気付きました。SQLiteOpenHelperサブクラスを使用したテストの最初の実行の後、テーブルが既に存在していたため、後続のテストでSQLiteExceptionを取得し続けました。また、「Path」というファイルと、地元のリポジトリに座っている「Path-Journal」と呼ばれるファイルが表示されました。シャドウクラスがメモリ内データベースを使用しているという印象を受けていたので、これは私を混乱させました。
Shadow Classの問題は次のとおりです。
database = SQLiteDatabase.openDatabase( "path", null, 0 );
getReadableAdataBase()とgetWriteAbledataBase()の両方で。実際のsqliteopenhelperがメモリ内データベースを作成できることを知っていました。ソースを見て、それがどのように行われるかを確認した後、上記の行を次のように置き換えました。
database = SQLiteDatabase.create( null );
その後、すべてが機能しているようです。行を挿入して読むことができます。
うまくいけば、これは他の誰かに役立ちます。
この質問に正確に関係していないが、誰かをさらに助けるかもしれない私に起こった奇妙なことの1つは、私もjmockitを使用しており、同じクラスで1つのテストでそれを使用していたことです。しかし、何らかの理由で、これは私のカスタムシャドウクラスを使用しませんでした。私はそのクラスのためにモッキートに切り替えました、そしてそれは正常に動作します。