상식닷컴
로그인
가입하기
2026년 상식닷컴 선정 식당 & 카페 리스트
2025년 2026년 신상 호텔 리스트
최근에 오픈한 호텔을 찾는다면 살펴보세요
일주일 식단표 어플
자동 일주일 식단표 어플
안드로이드
아이폰
주식 & 코인 차트의 신
1000만원으로 2000만원 만들기 프로젝트
수정하기 - Robolectric을 사용하여 비동기 작업을 테스트하는 방법은 무엇인가요?
닉네임
비밀번호
제목
내용
[이미지 업로드는 권한이 있는 사람만 가능. 하단 카톡으로 연락]
Robolectric은 Android의 단위 테스트 라이브러리로, Android 프레임워크 코드를 JVM 상에서 실행할 수 있게 해줍니다. 하지만 실제 안드로이드 디바이스가 아닌 환경에서 비동기 작업(예: `Handler`, `<a href='https://sangseek.com/sangseeks/AsyncTask/ko'>AsyncTask</a>`, `<a href='/sangseeks/Thread/ko'>Thread</a>`, `ExecutorService`, RxJava, LiveData 등)을 테스트할 때는 동기화 문제나 타이밍 문제 때문에 테스트가 제대로 동작하지 않는 경우가 종종 있습니다. 이럴 때 Robolectric이 제공하는 메인 루퍼(MainLooper), 스케줄러를 활용해 비동기로 예약된 작업(예: 메시지, Runnable 등)을 강제로 실행시키거나 제어함으로써 테스트를 안정적으로 수행할 수 있습니다. 아래는 Robolectric을 이용하여 비동기 작업을 테스트하는 일반적인 방법을 정리한 상세 설명입니다. --- 1. Robolectric 테스트 환경에서 비동기 작업의 문제점 - Android 앱이 동작할 때 UI Thread(Main Thread)는 메시지 큐(Message Queue)를 통해 <a href='https://sangseek.com/sangseeks/콜백/ko'>콜백</a>이나 Runnable이 실행됨 - Robolectric은 안드로이드 프레임워크중 Looper와 MessageQueue를 JVM에서 흉내내지만, 실제 디바이스처럼 자동으로 메시지가 처리되지 않음 - 따라서 `Handler.post(Runnable)`, `AsyncTask.execute()`, `LiveData`나 RxJava의 비동기 작업 등은 별도의 제어 없이는 테스트 중에 실행되지 않을 수 있음 - 이런 문제로 인해 테스트가 실패하거나 무한 대기 상태가 발생할 수 있음 --- 2. 로보렉틱에서 비동기 작업 제어를 위한 주요 API - `ShadowLooper` : Robolectric이 만들어낸 `Looper`에 대한 제어용 클래스. 메시지 큐를 조작해 예약된 작업을 실행시키거나 진행시킬 수 있음. - `ShadowLooper.getMainLooper()` : 메인 스레드인 기본 Looper의 쉐도우 객체를 가져옴. - `ShadowLooper.runToEndOfTasks()` : 메시지 큐에 스케줄된 모든 작업을 즉시 실행 - `ShadowLooper.idleOneTask()` : 메시지 큐에 하나의 작업만 실행 - `Robolectric.flushForegroundThreadScheduler()` : 메인 스레드 작업 스케줄러를 비움(face로 모든 작업 실행) - `Robolectric.flushBackgroundThreadScheduler()` : 백그라운드 스레드 작업 스케줄러 작업 실행 - `Robolectric.pauseMainLooper()` 및 `Robolectric.unPauseMainLooper()` : 메인 루퍼를 멈췄다가 재개 가능 --- 3. 일반적인 비동기 작업 테스트 패턴 3-1. Handler 또는 Runnable 비동기 처리 테스트 ```java @Test public void testHandlerPostRunnable() { Handler handler = new Handler(Looper.getMainLooper()); AtomicBoolean executed = new AtomicBoolean(false); handler.post(() -> executed.set(true)); // 실제로 Runnable이 메인 메시지 큐에서 처리되도록 실행 ShadowLooper.runMainLooperOneTask(); // 또는 ShadowLooper.getShadowMainLooper().runToEndOfTasks(); assertTrue(executed.get()); } ``` - `Handler.post()`로 예약된 Runnable은 메시지 큐에 들어가지만 자동 실행되지 않음 - `ShadowLooper.getShadowMainLooper().runToEndOfTasks()`를 호출해서 즉시 실행시키면 테스트 코드가 해당 Runnable 동작을 검증할 수 있음 3-2. AsyncTask 테스트 ```java @Test public void testAsyncTask() { AtomicBoolean done = new AtomicBoolean(false); MyAsyncTask task = new MyAsyncTask(() -> done.set(true)); task.execute(); // AsyncTask는 내부적으로 serialExecutor, 백그라운드 스레드, 메인 스레드 동기 때문에 // Robolectric 스케줄러를 먼저 플러시해 비동기작업 완료 처리 해야 함 Robolectric.flushBackgroundThreadScheduler(); Robolectric.flushForegroundThreadScheduler(); assertTrue(done.get()); } ``` - AsyncTask 내부는 백그라운드 작업 + 메인 스레드 후처리 순으로 동작함 - `flushBackgroundThreadScheduler()`와 `flushForegroundThreadScheduler()`를 호출해서 각각의 스케줄러 작업을 강제로 실행시킴 - 그렇지 않으면 작업이 백그라운드에서 처리되기 전에 검사하게 되어 테스트 실패함 3-3. LiveData 또는 HandlerThread 등 테스트 ```java @Test public void testLiveDataUpdate() { MutableLiveData<String> liveData = new MutableLiveData<>(); // Observer 등록 liveData.observeForever(value -> assertEquals("newValue", value)); // LiveData는 내부적으로 메인 루퍼 스케줄러 통해 값 전달되므로 liveData.postValue("newValue"); // 스케줄러 플러시 ShadowLooper.runMainLooperOneTask(); } ``` - LiveData는 postValue()를 호출하면 메인 스레드 메시지 큐에 전달 예약됨 - 따라서 메시지 큐에 있는 작업을 명시적으로 실행시켜야 observer가 데이터 변경을 정상 수신함 --- 4. RxJava, Coroutine 등과 결합한 비동기 테스트 시 주의점 - RxJava의 경우 Schedulers를 `Schedulers.trampoline()`으로 교체해서 동기 실행하게 변경하거나, 테스트 전용 Scheduler를 Injector 또는 RxJavaPlugins를 통해 설정 - Kotlin Coroutine은 Main Dispatcher를 `Dispatchers.Unconfined` 혹은 Robolectric Test에 맞춰 `Dispatchers.setMain` <a href='https://sangseek.com/sangseeks/Mockito/ko'>Mockito</a> 등의 룰 등을 써서 변경 후 테스트가 일반적 --- 5. 요약 및 팁 - Robolectric은 안드로이드 메시지 큐와 루퍼를 흉내내지만, 비동기 작업이 자동으로 실행되지 않아 명시적으로 스케줄러를 flush하거나 메시지큐를 실행시켜줘야 함 - `ShadowLooper.getShadowMainLooper()` 를 이용해 메시지 큐에 쌓인 동기 작업(Runnable, 메시지 등)을 즉시 실행 가능 - `Robolectric.flushForegroundThreadScheduler()` / `flushBackgroundThreadScheduler()`는 AsyncTask 등 작업 스케줄러를 진행하는 데 유용 - LiveData나 Handler 등의 비동기 콜백은 처리될 때까지 메시지 큐를 도는 로직을 넣어줘야 안정적인 테스트가 가능 - RxJava나 Coroutine 뷰 측면 테스트에서는 별도의 테스트 Scheduler 또는 Dispatcher 교체가 필요하므로 Robolectric과 별개로 핸들링 필요 --- 이처럼 Robolectric을 활용해서 비동기 코드를 테스트 할 때는 테스트 내에서 동기화 지점을 명확히 하여, '언제 비동기 작업이 완료되었는지'를 제어하는 것이 중요합니다. 이를 위해 위에서 설명한 `ShadowLooper` 와 `flushScheduler` API 등을 적극 활용하면 안정적이고 재현 가능한 단위테스트가 가능합니다.
이용안내
커뮤니티 이용안내
×
- 게시한 게시글로 발생하는 문제는 게시자에게 책임이 있습니다.
- 게시글이 타인/타업체의 저작권을 침해할 경우 모든 책임은 게시자에게 있습니다. 게시자가 모든 손해를 부담해야 합니다.
- 상식닷컴 운영자는 게시자와 상의하지 않고 게시글을 수정 또는 삭제할 수 있습니다.
- 상식닷컴 운영자는 깨끗한 커뮤니티 공간을 만드는 것이 1순위입니다.
수정하기
취소하기