| 일 | 월 | 화 | 수 | 목 | 금 | 토 |
|---|---|---|---|---|---|---|
| 1 | 2 | 3 | 4 | 5 | 6 | 7 |
| 8 | 9 | 10 | 11 | 12 | 13 | 14 |
| 15 | 16 | 17 | 18 | 19 | 20 | 21 |
| 22 | 23 | 24 | 25 | 26 | 27 | 28 |
- 푸시알림
- XCUITest
- java
- WDA
- iOS Class Chain
- XCUIElementStaticText
- xpath
- 포그라운드
- 자동화 테스트
- Appium Inspector
- appium
- Web Driver Agent
- XCode Console
- push notification
- foreground
- IOS
- Today
- Total
성장기의 히동
[Appium, iOS] 같은 로케이터를 사용하는 버튼을 눌렀을 때, 요소를 찾지 못한다는 에러가 발생하는 이유 본문
이번에 겪은 문제는 같은 accessibility id를 가진 "checkmark" 요소가 다른 화면에 보일 때 객체의 로케이터 값을 재설정 하지 않은 상태로 다시 한 번 click() 메서드를 수행할 때 요소를 찾지 못하는 에러다.


📍 에러 발생 상황
두 장의 사진에서 확인할 수 있는 체크 버튼이 있다. 다른 UI에 존재하지만, 같은 버튼이다.
이 체크 버튼의 accessibility id는 "checkmark"로 동일하다.
같은 로케이터를 사용하기 때문에, 이미 찾아둔 객체를 해당 화면에서 다시 클릭 한다고 해도 문제가 없을 거라고 생각해 아래와 같이 checkmark 객체를 재사용하도록 코드를 작성했다. 객체 타입이 없는 이유는 클래스 변수로 선언했기 때문이다.
- enterBasicInformationRoutineAndToDo(String routineTitle, String toDotitle)
: 루틴 이름과 할 일 이름을 입력받아 관련 TC에서 공통적으로 필요한 초기 동작을 함수로 뺐다. - checkmark는 다른 객체와 마찬가지로 WebElement 이다.
💭 기대 결과
로케이터가 같은 객체이기 때문에, 첫 번째 사진에서 체크 버튼을 click하고 두 번째 버튼에서 같은 객체로 click 메서드를 수행해도, 정상적으로 동작한다.
❌ 실제 결과
checkmark 요소를 찾지 못했다는 에러 발생

@Test
public void 루틴_액션_할일_모두_입력() {
String routineTitle = "루틴 생성 테스트 - 루틴 이름과 할일 이름 모두 등록";
String toDoTitle = "루틴 생성 시 할일 이름이 있을 경우";
enterBasicInformationRoutineAndToDo(routineTitle, toDoTitle);
checkmark = driver.findElement(accessibilityId("checkmark"));
// 할 일 생성
checkmark.click();
// 루틴 생성
checkmark.click();
WebElement createdRoutine = driver.findElement(accessibilityId(routineTitle));
assertEquals(createdRoutine.getAttribute("name"), routineTitle);
createdRoutine.click();
WebElement createdTodo = driver.findElement(accessibilityId(toDoTitle));
assertEquals(createdTodo.getAttribute("name"), toDoTitle);
}
💡실패 원인 분석
요소의 Stale(오래된) 상태에 대해 알 필요가 있었다.
요소는 화면 단위로 분리되어 관리되며, 화면을 벗어나거나 DOM(Document Object Model) 구조가 변경되면 기존 요소는 Stale 상태가 된다.
사실 앞서 발생한 에러는, Stale Element Reference Exception에 더 가까웠을 것이다.
이번 문제는 새 화면으로 이동해서 다른 화면이 로드된 경우다.
즉, 화면 단위로 View 객체가 새로 생성되므로 기존 화면의 요소는 Stale 상태가 된 것이다.
같은 Accessibility Id를 공유하더라도, 다른 화면의 요소니 "다른" 요소인 것이다.
이 문제를 해결하는 방법의 핵심은 "Stale 된 상태의 요소가 아닌, 해당 화면의 유효한 요소를 다시 찾아주는 것" 이다.
따라서 아래와 같이 코드를 수정했다.
루틴 생성 화면에서의 checkmark를 다시 찾아주는 방식으로 해결할 수 있었다.
@Test
public void 루틴_액션_할일_모두_입력() {
String routineTitle = "루틴 생성 테스트 - 루틴 이름과 할일 이름 모두 등록";
String toDoTitle = "루틴 생성 시 할일 이름이 있을 경우";
enterBasicInformationRoutineAndToDo(routineTitle, toDoTitle);
checkmark = driver.findElement(accessibilityId("checkmark"));
// 할 일 생성
checkmark.click();
checkmark = driver.findElement(accessibilityId("checkmark"));
// 루틴 생성
checkmark.click();
WebElement createdRoutine = driver.findElement(accessibilityId(routineTitle));
assertEquals(createdRoutine.getAttribute("name"), routineTitle);
createdRoutine.click();
WebElement createdTodo = driver.findElement(accessibilityId(toDoTitle));
assertEquals(createdTodo.getAttribute("name"), toDoTitle);
}
🌻후기
개발하면서 객체를 사용하던 습관이 남아있어 발생한 실수같다.
개발할 때는 DB에서 객체를 가져온 뒤에 DB를 변경해도, 객체는 변경 전 값을 고스란히 가지고 있기 때문에 객체를 항상 스냅샷을 저장하기도 하고, 임시 값을 저장하기도 하는 변수로 활용했었다.
설령 해당 데이터가 DB에서 사라지더라도, 객체는 삭제되기 전의 값을 유지하며 객체 자체를 삭제하기 전까지는 지속적으로 접근할 수 있었다.
하지만, WebElement는 화면에서 사라진 요소에는 접근할 수 없도록 하는 것이 새로웠고 앞으로 적응해나가야 할 부분이라고 느꼈다.
이번 문제를 경험 삼아, 이후로는 특정 요소의 value, name과 같은 attribute가 필요한 경우 String에 따로 저장해두면서 사용한다.
'☁️ QA' 카테고리의 다른 글
| [Appium, iOS] 푸시 알림 배너를 OCR로 검증하는 방법 - tesseract, tess4j / OCR 자동화 (1) | 2025.12.12 |
|---|---|
| [Appium, iOS] 포그라운드에서 iOS 앱 푸시 알림 테스트 - 알림센터에 등록되지 않는 경우 (0) | 2025.10.23 |
| [Appium, iOS] TypePickerWheel을 조작할 때 발생한 에러 직면기 및 Locator 리팩토링 (0) | 2025.10.15 |
| [QA/TC] 앱 테스트 중 기능 및 UI 변경 반영 TC 추가 및 변경 (2) | 2025.09.26 |
| [Appium] 같은 계층에 속해있으면서 같은 조건을 만족하는 StaticText를 어떻게 구분해낼 수 있을까? (1) | 2025.09.22 |