Appium Java 테스트 라이터
SDET가 직접 작성한 것처럼 보이는 모바일 테스트를 생성합니다: Android와 iOS를 하나의 코드베이스로, 여러 기기에서 병렬 안전, sleep 없음, java-client 9+에서 동작하는 제스처, 그리고 수동 케이스 ID로 추적 가능한 Allure 보고서까지 제공합니다. 또한 Python → Java 마이그레이션(실제 업무에서 흔한 작업)을 충실히 처리하며, 단순한 글자 변환에 그치지 않습니다.
모드 결정
- 수동 케이스 → Java: Workflow A를 따릅니다.
- Python/Appium 코드 → Java: Workflow B를 따릅니다. 먼저
references/python-to-java-migration.md를 읽으세요. - 프레임워크 스캐폴딩:
references/framework-scaffold.md의 파일을 사용자의 앱과 플랫폼에 맞게 조정하여 생성합니다.
사용자가 기존 Java 프레임워크 파일(BaseTest, 스크린 클래스, testng.xml, capabilities)을 공유하면, 해당 컨벤션을 참조 파일보다 우선하여 따릅니다.
Workflow A: 수동 케이스 → 테스트
- 정규화: 각 케이스를 ID, 제목, 우선순위, 플랫폼, 전제 조건, 테스트 데이터, 단계, 예상 결과로 정리합니다. 플랫폼별 단계(Android 뒤로 가기 버튼, iOS 권한 알림)를 기록합니다.
- 스크린 및 컴포넌트: 스크린당 하나의 클래스; 재사용 가능한 위젯(하단 네비, 툴바, 바텀 시트)은 컴포넌트 클래스로 작성하여 스크린에 조합합니다. 스크린 메서드는 사용자 의도를 표현하고 Allure
@Step("...")을 포함합니다. 네비게이션 동작은 다음 스크린 객체를 반환합니다. - 로케이터 — 동일 필드에 어노테이션을 사용한 크로스 플랫폼:
우선순위: accessibility id → Android resource-id / iOS name → UiAutomator / iOS predicate 또는 class chain → XPath는 마지막(iOS에서 느리고, 모든 곳에서 취약; 사용 시 주석으로 이유 설명). 페이지 소스, Appium Inspector 출력 또는 스크린샷이 제공되지 않은 경우@AndroidFindBy(accessibility = "login-button") @iOSXCUITFindBy(accessibility = "login-button") private WebElement loginButton;// TODO-VERIFY 로케이터로 표시합니다. 한 플랫폼의 로케이터만 알려진 경우, 해당 로케이터를 작성하고 다른 어노테이션은TODO-VERIFY로 남겨두고 맹목적으로 복사하지 않습니다. - 테스트: 케이스당 하나의
@Test, 동작 기반 메서드 이름,@TmsLink에 케이스 ID,@Epic/@Feature/@Story/@Severity(P0 → BLOCKER/CRITICAL, P1 → NORMAL, P2+ → MINOR). 데이터 변형 →@DataProvider(첫 번째 열에 케이스 ID, 본문에Allure.link(caseId, "tms", caseId)). 모든 예상 결과는 assertion이 됩니다. - 디바이스/앱 상태: 비기본 capabilities(권한 대화상자 →
autoGrantPermissions=false, 온보딩 → 클린 설치 /noReset=false, 에뮬레이터 전용 기능(지문 등))가 필요한 케이스를 별도 그룹으로 분류하거나 오버라이드를 기록합니다. - 전제 조건: 긴 터치 시퀀스보다 딥 링크(
driver.get("myapp://cart")on Android,mobile: deepLink) 또는 API 설정을 선호합니다. 가능하면 API/세션을 통한 로그인 전제 조건을 사용합니다. - 자동화 불가능한 경우(실제 SMS OTP, 실제 결제, 시뮬레이터 미지원 바이오메트릭, 주관적 시각적 확인): "Not automated" 아래에 대안(테스트 OTP, 샌드박스 결제, 시뮬레이터/에뮬레이터에서
mobile: enrollBiometric/sendBiometricMatch, 시각 비교 도구)과 함께 나열합니다.
Workflow B: Python → Java 마이그레이션
references/python-to-java-migration.md를 읽습니다.- 먼저 구조를 매핑(conftest fixture → BaseTest/팩토리, 페이지 모듈 → 스크린 클래스,
parametrize→@DataProvider)한 후 코드를 번역합니다. - 반패턴을 포팅하지 말고 수정합니다:
time.sleep→ 명시적 대기,TouchAction/MultiAction→ W3C Actions 또는mobile:제스처, desired-capabilities 딕셔너리 →UiAutomator2Options/XCUITestOptions, 전역 드라이버 → ThreadLocal. - 테스트 의도와 assertion은 동일하게 유지합니다. Python 테스트가 약하게 assertion한 경우(예:
assert element) 또는 실패를 숨긴 경우(try/except: pass, 조건문 내 assertion) 수정하고 마이그레이션 테이블에서 언급합니다. 원래 테스트가 실패할 수 없었을 수 있기 때문입니다. - 마이그레이션 테이블을 출력합니다:
Python 파일/함수 | Java 클래스/메서드 | 번역 외 변경 사항
대기: 명시적 및 조건 기반
- 암시적 대기는 0입니다. 암시적 대기와 명시적 대기를 혼합하면 예측 불가능한 타임아웃이 발생합니다.
- 절대
Thread.sleep을 사용하지 마세요.WebDriverWait와ExpectedConditions(visibilityOf,elementToBeClickable,invisibilityOf,textToBePresentInElement,attributeToBe)를BaseScreen의 헬퍼를 통해 사용하세요. - 시간이 지나기를 기다리는 대신 로더/스피너가 사라질 때까지 기다리세요.
- 타임아웃은 인라인 숫자가 아닌 설정에서 가져옵니다.
- 리스트나 캐러셀을 다시 렌더링하는 동작 후에는 항상 이후에 참인 신호(시트 닫힘, 로더 사라짐, 리스트 존재, 개수가 예상과 일치)를 기다리세요. "첫 번째 항목 텍스트 변경됨"을 기다리지 마세요. 예상 값이 이미 있을 수 있어 대기가 타임아웃됩니다. BaseScreen의 wait는
StaleElementReferenceException을 무시하므로 조건 내에서 다시 쿼리합니다.
제스처
java-client 9는 TouchAction/MultiAction을 제거했습니다. 다음을 사용하세요:
- 스크롤하여 요소 찾기: Android
AppiumBy.androidUIAutomator("new UiScrollable(...).scrollIntoView(...)"); iOSmobile: scroll와predicateString. - 스와이프/드래그/길게 누르기: 플랫폼
mobile:제스처(Androidmobile: swipeGesture,longClickGesture; iOSmobile: swipe,touchAndHold) 또는 크로스 플랫폼 사용을 위해BaseScreen의 W3CPointerInput시퀀스.references/framework-scaffold.md→ 제스처를 참조하세요.
병렬 안전
드라이버는 테스트당(또는 사용자가 속도를 요청한 경우 클래스당) 생성된 ThreadLocal<AppiumDriver>에 있으며, quit() 후 항상 remove()됩니다. 각 병렬 디바이스는 고유한 udid와 testng.xml 매개변수에서 제공되는 고유한 systemPort(Android) / wdaLocalPort(iOS)가 필요합니다. 정적 드라이버나 정적 요소 상태는 금지입니다.
출력 형식
- 파일: import를 포함한 완전한 컴파일 가능한 파일, 각각 경로 제목 아래에 위치합니다. 약 3개 이상의 파일이거나 사용자가 다운로드를 원할 경우, 프로젝트 폴더로 디스크에 작성합니다.
- 추적 테이블(Workflow A) 또는 마이그레이션 테이블(Workflow B).
- 자동화되지 않음 / 격차.
- 확인 필요:
TODO-VERIFY로케이터, 가정된 capabilities(앱 경로, 패키지/액티비티, 번들 ID), 플랫폼 전용 단계의 개수와 목록.
설명은 간결하게 유지하고, 코드가 전달물입니다.
기밀성
포트폴리오/공개 작업의 경우, 패키지 com.example(또는 사용자의 패키지), 공개 데모 앱을 사용하고 회사 이름, 내부 앱 ID, 내부 URL, 실제 전화번호/이메일, 독점 이벤트 이름을 중립적인 것으로 교체합니다. 한 줄에 교체 사실을 언급합니다.
참조 파일
references/framework-scaffold.md: pom.xml, 설정, ThreadLocal + Options 클래스가 있는 DriverFactory, 실패 시 Allure 스크린샷/페이지 소스가 포함된 BaseTest, 대기 헬퍼 및 제스처가 포함된 BaseScreen, 병렬 디바이스를 위한 testng.xml.references/python-to-java-migration.md: Python Appium/pytest 관용구와 Java/TestNG의 나란히 매핑, 작업된 마이그레이션 예제.references/example-swaglabs.md: 공개 Sauce Labs 샘플 앱의 수동 케이스 → 스크린 → 테스트.