2016-04-24 70 views
1

我寫了一個ContentProvider來處理本地sqlite數據庫上的query/insert/update/deleteAndroid Content Provider奇怪行爲測試

出於測試目的,我寫了幾個測試:

TestMovieContract.java : for testing MovieContract class 
TestMovieDBHelper.java : for testing MovieDBHelper class 
TestUriMatcher.java : for testing UriMatcher inside MovieContentProvider class 
TestProvider.java  : for testing MovieContentProvider class 

當我單獨運行這些測試,他們都獲得通過,但是當我運行所有這些測試的一個失敗。它失敗的斷言語句是:

returnedUri = mContext.getContentResolver().insert(
     movieInsertUri, 
     sampleMovieValues 
); 

assertNotNull("the values have not been inserted into " + MovieContract.MovieEntry.TABLE_NAME, returnedUri); 

當我檢查執行這個特定的測試,當我看到一個異常的logcat:

04-24 19:16:00.086 6938-6963/com.example.android.popularmovies.app I/TestRunner: started: testAndroidTestCaseSetupProperly(com.example.android.popularmovies.app.data.TestProvider) 
04-24 19:16:00.104 6938-6963/com.example.android.popularmovies.app I/TestRunner: finished: testAndroidTestCaseSetupProperly(com.example.android.popularmovies.app.data.TestProvider) 
04-24 19:16:00.104 6938-6963/com.example.android.popularmovies.app I/TestRunner: passed: testAndroidTestCaseSetupProperly(com.example.android.popularmovies.app.data.TestProvider) 
04-24 19:16:00.104 6938-6963/com.example.android.popularmovies.app I/TestRunner: started: testDelete(com.example.android.popularmovies.app.data.TestProvider) 
04-24 19:16:00.122 6938-6963/? E/SQLiteLog: (1032) statement aborts at 33: [INSERT INTO movie(popularity,vote_average,original_title,backdrop_url,movie_id,original_lang,image_url,overview,title,is_adult,release_date,vote_count,is_favorite,genre_ids) VALUES (?, 
04-24 19:16:00.122 6938-6963/? E/SQLiteDatabase: Error inserting popularity=8.3 vote_average=5.2 original_title=Some Android backdrop_url=http://mybackimage.com/44.png movie_id=40443 original_lang=en image_url=http://someimage.com/33.jpg overview=This is a sample overview title=Very First Android is_adult=true release_date=2015-05-23 vote_count=33345 is_favorite=true genre_ids=23,1,5 
               android.database.sqlite.SQLiteReadOnlyDatabaseException: attempt to write a readonly database (code 1032) 
                at android.database.sqlite.SQLiteConnection.nativeExecuteForLastInsertedRowId(Native Method) 
                at android.database.sqlite.SQLiteConnection.executeForLastInsertedRowId(SQLiteConnection.java:780) 
                at android.database.sqlite.SQLiteSession.executeForLastInsertedRowId(SQLiteSession.java:788) 
                at android.database.sqlite.SQLiteStatement.executeInsert(SQLiteStatement.java:86) 
                at android.database.sqlite.SQLiteDatabase.insertWithOnConflict(SQLiteDatabase.java:1471) 
                at android.database.sqlite.SQLiteDatabase.insert(SQLiteDatabase.java:1341) 
                at com.example.android.popularmovies.app.data.MovieContentProvider.insert(MovieContentProvider.java:197) 
                at android.content.ContentProvider$Transport.insert(ContentProvider.java:263) 
                at android.content.ContentResolver.insert(ContentResolver.java:1231) 
                at com.example.android.popularmovies.app.data.TestProvider.testDelete(TestProvider.java:308) 
                at java.lang.reflect.Method.invoke(Native Method) 
                at junit.framework.TestCase.runTest(TestCase.java:168) 
                at junit.framework.TestCase.runBare(TestCase.java:134) 
                at junit.framework.TestResult$1.protect(TestResult.java:115) 
                at junit.framework.TestResult.runProtected(TestResult.java:133) 
                at junit.framework.TestResult.run(TestResult.java:118) 
                at junit.framework.TestCase.run(TestCase.java:124) 
                at android.test.AndroidTestRunner.runTest(AndroidTestRunner.java:191) 
                at android.test.AndroidTestRunner.runTest(AndroidTestRunner.java:176) 
                at android.test.InstrumentationTestRunner.onStart(InstrumentationTestRunner.java:555) 
                at android.app.Instrumentation$InstrumentationThread.run(Instrumentation.java:1879) 
04-24 19:16:00.122 6938-6963/? W/SQLiteLog: (28) file unlinked while open: /data/user/0/com.example.android.popularmovies.app/databases/movie.db 

有一個在這篇日誌,我認爲年底的警告很重要。它顯示數據庫文件未鏈接。我檢查了我的所有代碼,以查看任何數據庫連接的正確關閉。

我的問題是爲什麼當我運行TestProvider.java時測試通過,但是當我運行所有這些時失敗了?我該如何解決它?

UPDATE

我做了小改動的地方我斷言失敗的面積和克隆的插入語句。新代碼如下所示:

returnedUri = mContext.getContentResolver().insert(
     movieInsertUri, 
     sampleMovieValues 
); 

returnedUri = mContext.getContentResolver().insert(
     movieInsertUri, 
     sampleMovieValues 
); 

assertNotNull("the values have not been inserted into " + MovieContract.MovieEntry.TABLE_NAME, returnedUri); 

令人驚訝的所有測試都通過,使我覺得有可能的東西引擎蓋下是錯誤的。我很感激,如果有人能幫助我搞清楚了這一點

+0

你使用模擬器還是真實設備?它是否植根?它有多少內存? –

+0

@MaximG模擬1G內存 – Pooya

回答

0

問題可以用的ContentProvider的多個實例,使用ContentProvider.shutdown();

「當你調用一個ContentProvider的測試方法,但是,ContentProvider的實例啓動後繼續運行即使後續測試實例化另一個ContentProvider,也會產生衝突,因爲這兩個實例通常針對相同的基礎數據源(例如,sqlite數據庫)運行「

檢查docs

例子:

@Override 
@TargetApi(11) 
public void shutdown() { 
    mOpenHelper.close(); 
    super.shutdown(); 
} 
+0

我在我的內容提供者類中關閉覆蓋,我應該明確調用它嗎? – Pooya

+0

我已經實現了shutdown方法,但在我的測試中,我無法訪問內容提供者實例來顯式調用shutdown() – Pooya

+0

嘗試在tearDown()方法中添加調用。 –

1

實現關機()爲馬克西姆摹提到確實需要照顧的問題,但你需要確保你的代碼調用它在每個測試。棘手的部分是通過ContentResolver訪問ContentProvider。

 mContext.getContentResolver() 
      .acquireContentProviderClient(uri) 
      .getLocalContentProvider() 
      .shutdown(); 

只要您的內容供應商不是外部供應商,這種方法就行得通。