Maestro Flakiness: 소스 코드 분석
Source: Dev.to

Maestro는 모바일 애플리케이션의 불안정성을 “수용한다”는 테스트 프레임워크로 자신을 홍보합니다.
하지만 실제 코드에서는 이것이 정확히 무엇을 의미할까요? 저는 소스를 직접 파헤쳐 보았습니다.
마케팅 약속
Maestro 문서에서:
“UI 요소가 항상 예상한 위치에 있지는 않으며, 화면 탭이 항상 통과하지도 않습니다. Maestro는 모바일 애플리케이션과 기기의 불안정성을 수용하고 이를 보완하려고 합니다.”
“테스트에sleep()호출을 여기저기 삽입할 필요가 없습니다. Maestro는 콘텐츠 로드에 시간이 걸릴 수 있음을 알고 자동으로 기다려 주지만(필요 이상으로 오래 기다리지는 않습니다).”
멋지게 들리죠. 실제 코드가 무엇을 하는지 살펴봅시다.
Source: Orchestra.kt
1. Element Finding – 하드코딩된 17초 타임아웃
tapOn: "Login"을 작성하면 Maestro는 한 번 보고 실패하지 않습니다. 지속적으로 폴링합니다. 하지만 얼마나 오래 폴링할까요?
class Orchestra(
private val maestro: Maestro,
private val lookupTimeoutMs: Long = 17000L, // Hardcoded: 17 seconds
private val optionalLookupTimeoutMs: Long = 7000L // Hardcoded: 7 seconds for optional
)
이것이 의미하는 바
- 모든 요소 조회는 기본적으로 17초까지 대기합니다.
- 선택적 요소는 7초까지 대기합니다.
- 이 값을 명령마다 변경할 수 없습니다.
느린 API 응답 때문에 30초를 기다리고 싶나요? 안 됩니다. 성능 테스트를 위해 3초 안에 빠르게 실패시키고 싶나요? 역시 불가능합니다.
2. 폴링 메커니즘 – 간단하지만 경직됨
Source: MaestroTimer.kt
fun withTimeout(timeoutMs: Long, block: () -> T?): T? {
val endTime = System.currentTimeMillis() + timeoutMs
do {
val result = block()
if (result != null) {
return result
}
} while (System.currentTimeMillis()
Note: 최대 대기 시간은 10초(10회 폴링 × 1초)입니다. 이 값은 구성할 수 없습니다.
7. 플랫폼 차이점: Android vs iOS
Maestro는 플랫폼마다 “settling”(정착) 방식을 다르게 처리합니다.
Android
Source: AndroidDriver.kt
// Checks if window is still updating
val windowUpdating = blockingStubWithTimeout.isWindowUpdating(...)
iOS
Source: IOSDriver.kt
// Uses screenshot comparison to detect animation end
val didFinishOnTime = waitUntilScreenIsStatic(SCREEN_SETTLE_TIMEOUT_MS)
두 접근 방식은 신뢰성 특성이 다르지만, 구성 가능성을 제공하지 않습니다.
요약: 하드‑코딩된 현실
| 매개변수 | 값 | 구성 가능? |
|---|---|---|
| 요소 조회 제한시간 | 17,000 ms | ❌ 아니오 |
| 선택적 요소 제한시간 | 7,000 ms | ❌ 아니오 |
| 탭 재시도 시도 횟수 | 2 | ❌ 아니오 |
| 최대 재시도 명령 | 3 | ❌ 아니오 |
| 스크린샷 차이 임계값 | 0.5 % | ❌ 아니오 |
| 정착 폴링 간격 | 200 ms | ❌ 아니오 |
| 정착 최대 반복 횟수 | 10 | ❌ 아니오 |
waitUntilVisible 제한시간 | 10,000 ms | ❌ 아니오 |
평결
Maestro의 “내장 플라키니스 처리”는 순수 XCUITest나 Espresso보다 더 많은 일을 하지만, 하드코딩된 값이 있는 일괄 해결책이다.
- 코드가 깔끔하고 접근 방식이 타당하다.
- 탈출구가 없다는 것은 기본값이 앱에 맞지 않을 때 해결책이 없다는 뜻이다.
이는 반드시 나쁜 것은 아니며—단순함을 위한 트레이드오프이다. 그러나 마케팅은 실제 코드가 제공하는 것보다 더 높은 지능과 적응성을 암시한다.
주요 소스 파일
| File | Description |
|---|---|
Orchestra.kt | 명령 실행 및 타임아웃 |
Maestro.kt | 탭 로직 및 재시도 |
MaestroTimer.kt | 폴링 기본 기능 |
ScreenshotUtils.kt | 스크린샷 비교 |
Commands.kt | 명령 정의 |
우리는 단순히 문제를 지적하는 것이 아닙니다
우리는 Maestro의 YAML 구문을 사랑합니다—수년간 모바일 테스트 자동화에 일어난 최고의 변화라고 할 수 있습니다: 간단하고, 가독성이 좋으며, 버전‑컨트롤에 친화적입니다.
하지만 실행 엔진에는 실제 제한 사항이 있습니다:
- 고정된 타임아웃
- 구성 가능성 없음
- 플랫폼 간 불일치
그래서 우리는 이를 해결하기 위해 무언가를 만들고 있습니다.
Appium의 검증된 인프라 위에서 Maestro YAML 테스트를 실행하는 오픈‑소스 엔진으로, 다음을 제공합니다:
- 설정 가능한 타임아웃
- 실제 디바이스 지원
- 매직 넘버 없음
이곳을 주목해 주세요.
