2017-09-20 5 views
0

私のDBをテストする場合、私は次のエラーを取得:エラーデータベースリポジトリをテスト - SQLBrite、SQLDelight

  • SQLiteDiskIOException:ディスクI/Oエラー(HTCの欲望620)
  • SQLiteReadOnlyDatabaseException:読み取りを書き込もうとすると単体データベース(Moto g2)

明らかに私はそれをテストします。 アプリを実行するとエラーは発生しません。それでも、アプリをテストできない場合は、おそらくコードに問題があります。

このアプリケーションでは、SQLDelightとSQLBriteがうまくいっていると思われる2つのライブラリを使用しています。

何が起きているのかをよりよく理解するために、データパッケージ内のファイルの簡単な説明を記載します。

-+-data-+ 
|  |-manager-+ 
|  |   |-LocationManager 
|  |   |-RunManager 
|  |-model-+ 
|  |  |-Location 
|  |  |-Run 
|-DatabaseContract 
|-DataRepository 
|-MyDBHelper 

ファイルLocationRunはSQLDelightによって生成された行のモデルです。 LocationManagerおよびRunManagerを使用すると、sqlStatementsを生成して対応するテーブルにデータを挿入または削除できます。 RunManagerの下にはLocationMangagerが似ています。

public class RunManager { 

    public final Run.InsertRun insertRace; 
    public final Run.DeleteRun deleteRun; 
    public final Run.DeleteRunWhereTimeSmallerThan deleteRunWhereTimeSmallerThan; 

    public RunManager(SQLiteDatabase db) { 
     insertRace = new Run.InsertRun(db); 
     deleteRun = new Run.DeleteRun(db); 
     deleteRunWhereTimeSmallerThan = new Run.DeleteRunWhereTimeSmallerThan(db); 
    } 

} 

MyDBHelperは、標準的な方法でSQLiteOpenHelperを拡張します。

public class MyDbHelper extends SQLiteOpenHelper { 

    private static final int DATABASE_VERSION = 1; 
    public static final String DATABASE_NAME = "runner.db"; 

    private static MyDbHelper INSTANCE = null; 

    private MyDbHelper(Context context) { 
     super(context, DATABASE_NAME, null, DATABASE_VERSION); 
    } 

    public static MyDbHelper getInstance(Context context) { 
     if (INSTANCE == null) { 
      INSTANCE = new MyDbHelper(context); 
     } 
     return INSTANCE; 
    } 

    @Override 
    public void onCreate(SQLiteDatabase sqLiteDatabase) { 
     // create table (omitted) 
    } 

    @Override 
    public void onUpgrade(SQLiteDatabase sqLiteDatabase, int oldVersion, int newVersion) { 
     // upgrade table (omitted) 
    } 
} 

データリポジトリは、さまざまな挿入操作とクエリ操作を集約します。

public class DataRepository implements DatabaseContract { 

    private static DataRepository INSTANCE = null; 

    BriteDatabase briteDatabase; 
    LocationManger locationManger; 
    RunManager runManager; 

    private DataRepository(Context context) { 
     SqlBrite sqlBrite = new SqlBrite.Builder().build(); 
     MyDbHelper helper = MyDbHelper.getInstance(context); 
     briteDatabase = sqlBrite.wrapDatabaseHelper(helper, Schedulers.io()); 
     locationManger = new LocationManger(briteDatabase.getWritableDatabase()); 
     runManager = new RunManager(briteDatabase.getWritableDatabase()); 
    } 

    public static DataRepository getInstance(Context context) { 
     if (null == INSTANCE) { 
      INSTANCE = new DataRepository(context); 
     } 
     return INSTANCE; 
    } 

    @Override 
    public Observable<List<Run>> getAllRun() { 
     return briteDatabase.createQuery(
       Run.TABLE_NAME, 
       Run.SELECT_ALL 
     ).mapToList(Run.MAPPER::map); 
    } 

    @Override 
    public Observable<List<Location>> getLocationsForRun(long id) { 
     return briteDatabase.createQuery(
       Location.TABLE_NAME, Location.FACTORY.selectAllByRace(id).statement 
     ).mapToList(Location.MAPPER::map); 
    } 

    @Override 
    public long insertRun(double distance, long duration, double avgSpeed, long timestamp) { 
     runManager.insertRace.bind(distance, duration, avgSpeed, timestamp); 
     return briteDatabase.executeInsert(Run.TABLE_NAME, runManager.insertRace.program); 
    } 

    @Override 
    public void deleteRun(long id) { 
     runManager.deleteRun.bind(id); 
     briteDatabase.executeUpdateDelete(Run.TABLE_NAME, runManager.deleteRun.program); 
    } 

    @Override 
    public void deleteRunWhereTimestampSmallerThan(long timestamp) { 
     runManager.deleteRunWhereTimeSmallerThan.bind(timestamp); 
     briteDatabase.executeUpdateDelete(Run.TABLE_NAME, runManager.deleteRunWhereTimeSmallerThan.program); 
    } 

    @Override 
    public long insertLocation(long raceId, double lat, double lng, double alt, long timestamp) { 
     locationManger.insertLocation.bind(raceId, lat, lng, alt, timestamp); 
     return briteDatabase.executeInsert(Location.TABLE_NAME, locationManger.insertLocation.program); 
    } 

    public Observable<List<SingleRun>> getAllSingleRunModels() { 
     return briteDatabase.createQuery(
       Run.TABLE_NAME, 
       Run.SELECT_ALL 
     ).mapToList(Run.MAPPER::map) 
     // omitted 

} 

今質問の主要部分です。今のところ、私は以下のテストケースを書いて、上にリストされているエラーを実行します。 興味深いことに、テストを別々に実行しているときにエラーは発生せず、すべてのテストが合格します。

@RunWith(AndroidJUnit4.class) 
@LargeTest 
public class DataRepositoryTest { 

    private Context context; 
    private DataRepository mDataRepository; 

    @Before 
    public void setUp() { 
     context = InstrumentationRegistry.getTargetContext(); 
     context.deleteDatabase(MyDbHelper.DATABASE_NAME); 
     mDataRepository = DataRepository.getInstance(InstrumentationRegistry.getTargetContext()); 
    } 

    @Test 
    public void testPreConditions() { 
     Assert.assertNotNull(context); 
     Assert.assertNotNull(mDataRepository); 
    } 

    @Test 
    public void testInsertRace() { // this test failes when all tests are run. 
     long raceID1 = mDataRepository.insertRun(5.0, 35, 3.5, 1000); 
     Assert.assertEquals(1, raceID1); 
     long raceID2 = mDataRepository.insertRun(10.0, 70, 3.5, 2000); 
     Assert.assertEquals(2, raceID2); 
     long locationID1 = mDataRepository.insertLocation(raceID1, 0.5, 0.5, 0, 1000); 
     Assert.assertEquals(1, locationID1); 
     long locationID2 = mDataRepository.insertLocation(raceID1, 0.5, 0.5, 0, 1001); 
     Assert.assertEquals(2, locationID2); 
     long locationID3 = mDataRepository.insertLocation(raceID1, 0.5, 0.5, 0, 1002); 
     Assert.assertEquals(3, locationID3); 
     long locationID4 = mDataRepository.insertLocation(raceID1, 0.5, 0.5, 0, 1003); 
     Assert.assertEquals(4, locationID4); 
     long locationID5 = mDataRepository.insertLocation(raceID2, 0.5, 0.5, 0, 2000); 
     Assert.assertEquals(5, locationID5); 
     long locationID6 = mDataRepository.insertLocation(raceID2, 0.5, 0.5, 0, 2001); 
     Assert.assertEquals(6, locationID6); 
     long locationID7 = mDataRepository.insertLocation(raceID2, 0.5, 0.5, 0, 2002); 
     Assert.assertEquals(7, locationID7); 
     long locationID8 = mDataRepository.insertLocation(raceID2, 0.5, 0.5, 0, 2003); 
     Assert.assertEquals(8, locationID8); 
    } 

    @Test 
    public void testRaceObservable() { 
     long raceID1 = mDataRepository.insertRun(5.0, 35, 3.5, 1000); 
     Run run1 = Run.FACTORY.creator.create(raceID1, 5.0, 35l, 3.5, 1000l); 
     Assert.assertEquals(1, raceID1); 
     long raceID2 = mDataRepository.insertRun(10.0, 70, 3.5, 2000); 
     Run run2 = Run.FACTORY.creator.create(raceID2, 10.0, 70l, 3.5, 2000l); 
     Assert.assertEquals(2, raceID2); 
     List<Run> expectedResult = Arrays.asList(run1, run2); 
     Assert.assertEquals(expectedResult, mDataRepository.getAllRun().blockingFirst()); 
    } 


} 

これは、さまざまなスレッドからDBにアクセスすることとは関係がありますが、問題の解決方法はわかりません。

答えて

1

あなたの問題はsetUpが二度目に実行するとき、DataRepository.getInstanceそれは新しいSQLiteOpenHelperを作成しません意味、古いデータリポジトリを返すことです。データベースを削除するときには、DataRepositoryとMyDbHelperのシングルトンもクリーンアップする必要があります。

@Before 
public void setUp() { 
    context = InstrumentationRegistry.getTargetContext(); 
    context.deleteDatabase(MyDbHelper.DATABASE_NAME); 
    mDataRepository = new DataRepository(InstrumentationRegistry.getTargetContext()); 
} 

// In DataRepository.java 
DataRepository(Context context) { 
    SqlBrite sqlBrite = new SqlBrite.Builder().build(); 
    MyDbHelper helper = new MyDbHelper(context); 
    briteDatabase = sqlBrite.wrapDatabaseHelper(helper, Schedulers.io()); 
    locationManger = new LocationManger(briteDatabase.getWritableDatabase()); 
    runManager = new RunManager(briteDatabase.getWritableDatabase()); 
} 

// In MyDbHelper.java 
MyDbHelper(Context context) { 
    super(context, DATABASE_NAME, null, DATABASE_VERSION); 
} 

は、代わりにすべてのシングルトンを使用してはいけません

関連する問題