Robolectric에서 UI 스레드에서의 실행을 어떻게 제어하나요?
_____A: Robolectric은 안드로이드 테스트 실행 시 실제 기기의 메인(UI) 스레드를 시뮬레이션합니다. 따라서 UI 스레드에서 실행되어야 하는 코드를 테스트할 때 별도의 스레드 전환 없이도 안전하게 실행할 수 있습니다. 필요에 따라 UI 스레드 실행을 제어하는 방법은 다음과 같습니다.
---
1. @UiThread 또는 @UiThreadTest 애노테이션 사용하기
- `@UiThread` : Robolectric 4.3부터 지원되며, 테스트 메소드가 UI 스레드에서 실행되도록 지정합니다.
- `@UiThreadTest` : 안드로이드 기본 테스트 프레임워크에서 공식 지원하는 애노테이션이며, Robolectric에서도 동작합니다.
```java
@RunWith(RobolectricTestRunner.class)
public class MyTest {
@Test
@UiThread
public void testOnUiThread() {
// 이 메소드 내부 코드가 UI 스레드에서 실행됩니다.
}
}
```
이 애노테이션을 사용하면 직접 핸들러나 `runOnUiThread`를 호출하지 않고도 UI 스레드 환경을 보장받을 수 있습니다.
---
2. `ShadowLooper`를 이용하여 작업 실행 및 제어하기
Robolectric은 내부적으로 `ShadowLooper`를 통해 메인 스레드(Looper)의 메시지 큐를 관리합니다.
- 작업 큐에 등록된 Runnable 실행 명령
```java
// UI 스레드의 메시지 큐 (Looper)를 가져옴
ShadowLooper shadowLooper = ShadowLooper.getShadowMainLooper();
// 등록된 모든 작업을 즉시 실행
shadowLooper.runToEndOfTasks();
```
- 특정 시점까지 지연된 작업 실행
shadowLooper.runOneTask();
```
이 방법을 이용하면 UI 스레드에서 비동기적으로 예약된 작업들을 테스트 내에서 명시적으로 수행할 수 있습니다.
---
3. `Activity`의 `runOnUiThread` 호출 직접 사용
Robolectric 환경에서도 `Activity.runOnUiThread` 호출이 실제 UI 스레드 스케줄처럼 작동하지만 테스트는 메인 스레드상에서 동작합니다.
```java
activity.runOnUiThread(() -> {
// UI 스레드에서 실행할 코드
});
shadowLooper.runToEndOfTasks(); // 필요 시 작업 강제 실행
```
---
4. `Robolectric.flushForegroundThreadScheduler()` 사용하기
UI 스레드와 유사한 프론트그라운드 스레드 스케줄러에 있는 모든 작업을 실행시키는 유틸리티 메소드입니다.
```java
Robolectric.flushForegroundThreadScheduler();
```
---
요약
| 방법 | 설명 | 사용 시점 |
|------------------------------|------------------------------------------------|-----------------------------------|
| `@UiThread`, `@UiThreadTest` | 테스트 메서드를 UI 스레드에서 실행하게끔 함 | UI 스레드 실행 환경 보장 필요 시 |
| `ShadowLooper.getShadowMainLooper()` | 메인 메시지 큐에 대기중인 작업 실행 및 제어 | 비동기 작업 강제 실행 또는 디버깅 시 |
| `activity.runOnUiThread()` | UI 스레드에서의 실행 요청 | UI 스레드 실행 코드를 명시적 호출 시 |
| `Robolectric.flushForegroundThreadScheduler()` | 프론트그라운드 스레드 스케줄러 작업 실행 | UI 관련 작업 모두 즉시 실행 필요 시 |
---
참고 : Robolectric은 실제 안드로이드 런타임과는 다르게 동작하므로, 복잡한 스레드 동기화가 필요한 로직은 추가적인 테스트 전략이나 실제 기기 테스트가 필요할 수 있습니다. 하지만 위 방법들로 대부분의 UI 스레드 실행 관련 테스트를 효과적으로 수행할 수 있습니다.
안드로이드에서는 UI와 관련된 작업은 반드시 메인 스레드에서 실행되어야 하기 때문에, 테스트 시에도 UI 스레드 환경을 적절히 시뮬레이션하거나 강제로 해당 스레드에서 실행해야 합니다.
Robolectric은 기본적으로 테스트 코드를 메인(UI) 스레드에서 실행하도록 설계되어 있습니다.
이를 통해 별도의 스레드 전환 없이도 UI와 관련된 작업을 안전하게 테스트할 수 있는데, 여기서 UI 스레드 실행을 제어하는 주요 방법들을 정리하면 다음과 같습니다.
1. @UiThreadTest 어노테이션 사용 Robolectric은 AndroidJUnitRunner와 달리 기본적으로 메인 스레드에서 테스트가 실행되기 때문에 보통 @UiThreadTest가 굳이 필요하지 않지만, 만약 명시적으로 UI 스레드에서 실행하여야 하는 테스트 임을 표시하고 싶다면 사용할 수 있습니다.
이 어노테이션을 사용하면 해당 테스트 메서드의 실행이 UI 스레드에서 이루어집니다.
```java @Test @UiThreadTest public void testUiThread() { // UI관련 작업 수행 } ``` Robolectric 최신 버전에서는 @UiThreadTest가 없어도 기본적으로 UI 스레드에서 실행되기 때문에 필수적이지는 않지만, 의도를 명확히 하기 위해 사용할 수 있습니다.
2. ShadowLooper와 runPaused를 활용한 작업 스케줄링 제어 Robolectric 내부에서는 메인 스레드의 메시지 큐를 `ShadowLooper`가 감시하며, 테스트 중 특정 시점에 실행할 작업 처리를 수동으로 제어할 수 있습니다.
예를 들어 UI 스레드에 포스트된 작업을 즉시 실행하거나 중지할 수 있습니다.
```java ShadowLooper mainLooper = Shadows.shadowOf(Looper.getMainLooper()); mainLooper.runToEndOfTasks(); // 큐에 쌓인 작업 모두 실행 mainLooper.pause(); mainLooper.runOneTask(); // 한 작업만 실행 ``` 이를 통해 UI 스레드에서 비동기(post, postDelayed 등)로 스케줄된 작업의 실행 시점을 상세히 제어할 수 있습니다.
3. @Config annotation과 schedulers 설정 조작 Robolectric의 `@Config` 어노테이션 옵션에서, 특정 스케줄러 동작 방식을 설정할 수 있지만 실제로 UI 스레드는 기본적으로 잘 처리됩니다.
주로 RxJava 같은 서드파티 스케줄러를 테스트할 때 사용됩니다.
4. runOnUiThread 혹은 Instrumentation 테스트의 runOnMainSync 대체 실제 Android Instrumentation 테스트에서는 `Instrumentation.runOnMainSync()`를 통해 UI 스레드에서 코드를 실행할 수 있으나, Robolectric은 JVM 환경에서 실행되므로 실제 메인 스레드가 아닌 자체 메인 루퍼를 사용합니다.
그렇기 때문에 UI 작업은 그냥 테스트 메서드 내에서 수행하면 되며, 필요 시 `ShadowLooper`를 활용해 예약 작업들의 실행 시기를 조작할 수 있습니다.
5. AsyncTask나 Handler를 사용할 때 테스트 중 실행 강제 AsyncTask는 기본적으로 메인 스레드에서 콜백이 수행되어야 하는데, Robolectric은 내장된 ShadowAsyncTask를 통해 이를 지원합니다.
AsyncTask 실행 후 `Runnable` 콜백 등을 제어할 때도 `ShadowLooper`로 UI 스레드 메시지 큐를 컨트롤할 수 있습니다.
--- 정리 - Robolectric은 기본적으로 테스트를 UI 스레드 환경에서 실행하기 때문에 따로 UI 스레드 전환 코드를 쓰지 않아도 됨 - UI 스레드에서 실행해야 할 테스트 메서드에는 `@UiThreadTest`를 사용할 수 있으나 필수 아님 - UI 스레드 메시지 큐의 작업 실행 제어는 `ShadowLooper`를 사용해 처리 - 별도의 UI 스레드 실행 메서드(runOnUiThread 등)는 필요하지 않으며, 해당 코드를 호출할 경우에도 Robolectric의 Shadow로 적절히 처리됨 따라서 Robolectric에서는 UI 관련 코드 테스트 시, 특별한 스레드 처리 없이 기본 테스트 코드 내에서 안전하게 UI 스레드 환경을 시뮬레이션하며, 메시지 루프 제어가 필요하면 `ShadowLooper`를 활용하여 UI 스레드 내 작업 실행 시점을 세밀하게 조절할 수 있습니다.
작성자:
김시우 [비회원]
| 작성일자: 1년 전
2025-05-26 03:51:44
조회수: 339 | 댓글: 0 | 좋아요: 0 | 싫어요: 0
조회수: 339 | 댓글: 0 | 좋아요: 0 | 싫어요: 0
내용이 부정확하다면 싫어요를 클릭해주세요.