이 글은 기존 운영했던 WordPress 블로그인 PyxisPub: Development Life (pyxispub.uzuki.live) 에서 가져온 글 입니다. 모든 글을 가져오지는 않으며, 작성 시점과 현재 시점에는 차이가 많이 존재합니다.
작성 시점: 2018-11-05
최근 앱 내부에 모델을 저장해야 되는 일이 있을 때에 Eventbus로 유명한 Greenrobot가 제작하는 ObjectBox 를 많이 활용한다.
Entity, 즉 ObjectBox와 프로젝트를 연결하는 Manager 라는 클래스를 별도로 제작하여 이 클래스 안에서 ObjectBox에 관련된 작업 (CRUD, 정렬, 검색 등)을 진행하고 하위 코드(ViewModel) 단에서 이 Manager 클래스를 Inject받아 RxJava로 활용하는 방식이다.
이 방식에 약간의 문제점이 있다면 하위 코드를 작성하기 전까지는 해당 Manager 클래스를 테스트하기 어렵다는 점인데, 다행히 ObjectBox는 JUnit를 통한 단위 테스트를 제공한다.
따라서 이 글에서는 간단히 JUnit로 ObjectBox 와 RxJava2를 테스트하는 방법을 살펴보려 한다.
테스트 코드의 언어는 Java를 사용했다.
ObjectBox에서는 JUnit로 테스트할 때에 OS(Windows / macOS / Linux)에 맞는 바이너리 파일을 받아와 mdb 파일을 생성하고 데이터를 실제로 넣는 작업을 진행한다.
먼저, JUnit 클래스를 만들고 작업이 시작되기 전과 후에 Objectbox에 대한 작업을 진행한다.
private static final File TEST_DIRECTORY = new File("objectbox-example/test-db");
private BoxStore mBoxStore;
@Before
public void setUp() throws Exception {
// delete database files before each test to start with a clean database
BoxStore.deleteAllFiles(TEST_DIRECTORY);
mBoxStore = MyObjectBox.builder()
// add directory flag to change where ObjectBox puts its database files
.directory(TEST_DIRECTORY)
// optional: add debug flags for more detailed ObjectBox log output
.debugFlags(DebugFlags.LOG_QUERIES | DebugFlags.LOG_QUERY_PARAMETERS)
.build();
}
@After
public void tearDown() throws Exception {
if (mBoxStore != null) {
mBoxStore.close();
mBoxStore = null;
}
BoxStore.deleteAllFiles(TEST_DIRECTORY);
}
@Before 가 붙은 setUp() 의 메서드 실행 결과로 BoxStore 객체가 생성되므로, Box 객체를 받아올 때에는mBoxStore.boxFor(Class)
를 실행하면 된다.
그 다음 @After 가 붙은 tearDown 에서는 테스트가 종료될 때 생성된 DB 파일을 지워 이전의 테스트 결과가 현재의 테스트 결과에 영향을 주지 않게 변경한다.
본 예제에서 테스트할 작업은 DB에서 시작 날짜와 종료 날짜 사이의 데이터를 날짜 기준으로 정렬하여 리스트를 가져오는 작업이다.
public Observable<List<CalendarData>> getCalendarDataList(Calendar startCalendar, Calendar endCalendar) {
return Observable.create(emitter -> {
int startDay = CalendarUtils.getFormatDay(startCalendar);
int endDay = CalendarUils.getFormatDay(endCalendar);
List<CalendarData> sorted = Stream.of(mBox.query()
.between(CalendarData_.formatDay, startDay, endDay)
.build()
.find())
.sortBy(value -> value.formatDay)
.toList();
emitter.onNext(sorted);
});
}
그리고 위 메서드에 대해 테스트 케이스를 작성하면, RxJava 구독을 성공했고 에러 없이 작업이 될 경우일 것이다.
@Test
public void getCalendarDataWeakList() {
TestObserver<List<CalendarData>> dataTestObserver = new TestObserver<>();
Calendar startCalendar = Calendar.getInstance();
Calendar endCalendar = Calendar.getInstance();
startCalendar.set(Calendar.DAY_OF_WEEK, 1);
endCalendar.set(Calendar.DAY_OF_WEEK, endCalendar.getActualMaximum(Calendar.DAY_OF_WEEK));
mCalendarDataManager.getCalendarDataList(startCalendar, endCalendar)
.subscribe(dataTestObserver);
dataTestObserver.assertSubscribed()
.assertNoErrors();
}
여기서 TestObserver
라는 클래스가 있는데, TestObserver 는 RxJava의 다양한 행동을 검증할 수 있는 메서드를 제공한다.
상기한 '구독을 성공했다' 에 대한 검증은 assertSubscribed()
를, 에러 없이 작업이 될 경우는 assertNoErrors()
를 사용했다.
위 테스트 케이스를 구동하면 아래와 같은 로그가 나온다.
[INFO ] Creating query #1 for CalendarData with 1 condition(s)
[INFO ] Finding using query #1
[INFO ] Parameters for query #1:
formatDay between 20181104 and 20181110
[INFO ] Creating query #2 for CalendarData with 1 condition(s)
[INFO ] Finding scalars using query #2
[INFO ] Creating query #3 for CalendarData with 1 condition(s)
[INFO ] Finding using query #3
[INFO ] Parameters for query #3:
formatDay between 20181104 and 20181110
Process finished with exit code 0
setUp 메서드에서 설정한 대로 ObjectBox가 표시하는 디버그 로그가 나오면서, 작업이 성공한다.
이처럼 ObjectBox와 RxJava가 실제 환경과 거의 같은 환경을 제공하는 덕분에, 하위 코드가 작성되기 전 해당 클래스에 대한 검증이 가능했다.