내 DB를 테스트 할 때 나는 다음과 같은 오류를 얻을 :오류 때 데이터베이스 저장소를 테스트 - SQLBrite, SQLDelight
- SQLiteDiskIOException : 디스크 I/O 오류 (HTC 디자 620)
- SQLiteReadOnlyDatabaseException : 읽기 쓰기 시도 -only 데이터베이스 (Moto g2)
분명히 장치에서 나는 그것을 테스트합니다. 앱을 실행할 때 오류가 발생하지 않습니다. 그래도 앱을 테스트 할 수 없다면 코드에 문제가있을 수 있습니다.
이 응용 프로그램은 SQLDelight와 SQLBrite를 함께 사용하기로되어있는 두 개의 라이브러리를 사용하므로이 질문을 다소 구체적으로 지정할 수 있습니다.
무슨 일이 벌어지고 있는지 더 잘 이해하기 위해 데이터 패키지에있는 파일에 대한 간단한 설명을 제공 할 것입니다.
-+-data-+
| |-manager-+
| | |-LocationManager
| | |-RunManager
| |-model-+
| | |-Location
| | |-Run
|-DatabaseContract
|-DataRepository
|-MyDBHelper
파일 Location
및 Run
은 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에 액세스하는 것과 관련이 있다고 가정합니다. 그러나이 문제를 해결하는 방법을 모르겠습니다.