디자인패턴
과거, 테스트 설계에 대한 고민 없이 대규모로 구현된 수천 개의 테스트 케이스를 유지보수했던 경험이 있습니다. 당시에는 로케이터가 조금만 변경돼도 테스트가 대규모로 실패했으며, 수정과 복구에 막대한 시간이 들었습니다. 이러한 상황은 테스트 자동화가 효율적이지 못한 설계로 인해 유지보수와 확장성에서 큰 어려움을 겪었기 때문입니다. 심지어 일부 프로젝트에서는 전체 테스트 구조를 새로 만들고 의존 관계를 제거한 뒤 처음부터 다시 설계하는 것이 더 효율적이라는 판단을 하기도 했습니다.
테스트 자동화에서 가장 중요한 두 가지는 유지보수성과 확장성입니다. 특히, UI가 자주 변경되거나 테스트 시나리오가 지속적으로 추가되는 환경에서는 이러한 특성이 더욱 요구됩니다. 이때, 설계에서 중요한 개념이 바로 OCP(개방-폐쇄 원칙)입니다. OCP는 코드를 수정하지 않고도 새로운 기능을 확장할 수 있도록 하는 원칙으로, 변화에 유연하게 대처할 수 있는 테스트 자동화 설계의 핵심입니다.
기존에 많이 사용되던 페이지 객체 패턴(Page Object Pattern)은 이러한 문제를 해결하기 위해 고안된 구조적 설계 방식입니다. 하지만 최근 제가 페이지 객체 패턴의 한계를 느끼고 도입한 JSON 기반 동적 테스트 설계는 유지보수성과 확장성 면에서 페이지 객체 패턴의 한계를 보완하는 동시에, OCP를 보다 충실히 준수하여 테스트 자동화의 본질적인 문제를 더 효과적으로 해결할 수 있는 접근 방식이라고 생각합니다.
이번 글에서는 제가 JSON 기반 동적 테스트 설계라고 부르고 있는 방식과 페이지 객체 패턴의 차이점, 각각의 장단점, 그리고 실제 사례를 바탕으로 두 방식의 기술적 차이를 분석하고 살펴보겠습니다.
UI 요소는 getter 메서드로 정의합니다. 페이지 동작은 예를 들어 login 같은 경우 메서드로 캡슐화되어 테스트에서 재사용됩니다. 테스트 코드는 loginPage.login(email, password)와 같이 추상화된 메서드를 호출하여 사나리오를 구현하는 방식입니다.
페이지 객체 패턴은 OOP(객체지향 프로그래밍) 철학에 기반한 설계입니다. UI 테스트에서 각 화면(Page)을 하나의 객체로 추상화하고, 해당 화면의 요소(Element)와 동작(Action)을 메서드로 캡슐화합니다. 그러나 새로운 동작을 추가하거나 로케이터가 변경될 경우 기존 메서드를 수정하거나 새로운 메서드를 추가해야 합니다. 이는 유지보수와 확장성을 저해할 수 있습니다.
전형적인 페이지 객체 패턴의 예시는 WebdriverIO에서 권장하는 방식과 과거(2022) 작성한 블로깅을 참고하셔도 좋습니다.
2-1. Json 파일
JSON 파일은 페이지 이름과 각 요소의 로케이터를 저장하는 역할만 수행합니다. 이를 통해 테스트 로직에서 사용할 UI 요소를 동적으로 참조할 수 있습니다.
2-2. BasePage 클래스
JSON 파일의 로케이터를 참조하여 동작을 동적으로 수행합니다. 이를 통해 로케이터는 JSON에서 관리하고, 동작은 (method) BasePage.validateAndPerformActions(page: any, elements: any): Promise<void>와 같이 재사용 가능한 코드로 관리합니다. BasePage 클래스의 constructor는 현재 실행 중인 테스트 환경이 Android인지 iOS인지 확인하여 this.platform 값을 설정합니다. 이를 통해 JSON 파일에서 플랫폼별로 적합한 로케이터를 동적으로 참조할 수 있도록 돕습니다.
2-3. 테스트 케이스 표현 방식
위 테스트 케이스는 JSON 파일과 BasePage를 활용하여 테스트 시나리오를 간결하고 직관적으로 작성한 예시입니다. JSON 파일에 로케이터를 정의하고 BasePage에서 공통 동작 메서드를 처리하여 테스트 코드에서 최소한의 작업으로 복잡한 시나리오를 구현할 수 있는 방식을 보여줍니다. 특징은 아래와 같습니다.
2-3-1. 직관적인 동작 정의
테스트 케이스에서 UI 요소에 수행할 액션(예: validate, input, click)을 간단히 명시합니다. 이로 인해 테스트 로직이 직관적이고 읽기 쉽게 작성됩니다.
2-3-2. JSON 로케이터 참조
UI 요소의 로케이터는 JSON 파일에 정의되며, 플랫폼(Android/iOS)에 따라 적절한 값을 BasePage가 동적으로 참조합니다. 이를 통해 UI 변경이 발생해도 테스트 로직을 수정하지 않고 JSON만 업데이트하면 됩니다.
2-3-3. 공통 메서드 재사용
BasePage.validateAndPerformActions 메서드는 다양한 테스트 케이스에서 재사용 가능하며, 액션 배열만 전달하면 테스트 시나리오를 쉽게 확장할 수 있습니다.
페이지 객체 패턴은 로케이터와 동작을 클래스 내부에 정의합니다. 이는 코드의 재사용성을 높이는 장점이 있지만 새로운 시나리오가 추가될 때마다 메서드를 추가해야 하며 코드가 점점 복잡해질 수 있습니다. 위 방식에서는 새로운 시나리오마다 추가적인 메서드 정의가 필요하고 로케이터를 변경하려면 클래스 내부 코드를 수정해야 합니다. JSON 기반 설계에서는 로케이터를 JSON에 저장하고, 동작은 공통 BasePage 클래스에서 처리합니다. 이를 통해 로케이터 추가 및 수정은 JSON 파일에서, 액션 추가 및 수정은 BasePage에서 이루어집니다.
즉 유지보수성과 확장성 관점에서 페이지 객체 패턴은 새로운 시나리오를 추가하려면 클래스 내부에 새로운 메서드를 정의해야 합니다. UI가 변경될 경우 메서드와 로케이터 모두 수정이 필요할 수도 있습니다. 하지만 JSON 기반 설계는 로케이터는 JSON 파일에 추가하고, 테스트 로직에서는 필요한 액션만 정의하면 됩니다. 로케이터가 변경되더라도 JSON 파일만 수정하면 됩니다.
OCP 관점에서는 페이지 객체 패턴은 기존 메서드의 수정이나 새로운 메서드의 추가가 필요할 수 있으므로 OCP 위반 가능성이 존재합니다. 하지만 JSON 기반 설계는 기존 코드를 수정하지 않고 JSON 파일과 테스트 로직만으로 테스트 시나리오 확장이 가능하므로 OCP를 준수합니다.
4-1. OCP(개방-폐쇄 원칙)란?
OCP(개방 폐쇄 원칙)는 기존 코드를 수정하지 않고 확장할 수 있어야 한다는 원칙입니다. JSON 기반 설계는 OCP를 아래와 같이 준수합니다.
새로운 시나리오 추가 시 JSON 파일에 로케이터를 추가하고, 테스트 케이스에서 액션을 정의하는 것만으로 시나리오를 확장할 수 있습니다. 또한 UI 변경 시 JSON 파일의 로케이터만 수정하면 되므로 기존 코드를 수정할 필요가 없습니다.
4-2. 페이지 객체 패턴의 OCP 위반 사례
페이지 객체 패턴에서는 다음과 같은 OCP 위반 사례가 발생할 수 있습니다. 문제 상황은 다음과 같습니다.
로그인 버튼에 로딩 스피너 검증이 추가된 경우 기존의 clickLoginButton() 메서드를 수정하거나, 새로운 clickLoginButtonWithSpinnerCheck() 메서드를 추가해야 합니다. 이는 기존 코드를 수정하게 되므로 OCP를 위반합니다. 즉 A, B 시나리오에서는 클릭 동작만 필요한 로직인데 C, D 시나리오에서는 클릭 외에 다른 동작까지 해야 할 경우 동일한 메서드를 사용할 수 없으므로 메서드를 추가로 구현하고 관리해야 합니다.
4-3. JSON 기반 설계의 해결 방법
메서드를 수정하거나 추가할 필요 없이 테스트 로직에 이미 정의된 메서드를 활용하여 새로운 동작만 추가하면 됩니다.
5-1. UI 변경 대응
기존 페이지 객체 패턴에서는 버튼의 XPath가 변경되면 클래스의 로케이터를 수정해야 하지만, JSON 기반 설계에서는 JSON 파일만 수정하면 됩니다.
5-2. 테스트 시나리오 확장
페이지 객체 패턴은 새로운 동작이나 검증이 추가될 때마다 클래스 메서드를 추가해야 하지만, JSON 기반 설계는 JSON에 데이터를 추가하고 테스트에서 호출만 하면 됩니다. 추가 동작이 필요하다면 공통 메서드 1개만 수정하면 됩니다.
5-3. 유지보수 호율성
페이지 객체 패턴은 UI와 비즈니스 로직의 변경이 많을수록 클래스 파일이 복잡해지고, 수정 작업이 늘어나지만 JSON 기반 설계는 변경 사항이 JSON 파일로 제한되므로 유지보수 작업이 단순화됩니다.
기존 페이지 객체 패턴은 각 UI 요소와 동작을 메서드로 정의하므로, 테스트 로직이 복잡해질수록 클래스 파일이 비대해지고 유지보수가 어려워질 수 있습니다. 반면, JSON 기반 동적 설계는 로케이터와 동작을 분리하여 이러한 문제를 효과적으로 해결하며, 테스트 코드를 시나리오 중심으로 간결하고 명확하게 작성할 수 있는 장점을 제공합니다.
특히 OCP(개방-폐쇄 원칙)를 준수하여 코드 수정 없이 새로운 테스트를 확장할 수 있다는 점에서 큰 강점을 가졌고 UI 변경 시에도 JSON 파일과 테스트 로직만 수정하면 되므로 유지보수가 간단하고 효율적입니다. 또한, 불필요한 페이지 클래스와 메서드 정의가 줄어들어 테스트 시나리오를 직관적으로 이해할 수 있습니다.
하지만 페이지 객체 패턴도 특정 프로젝트와 팀 구조에서는 여전히 적합한 선택일 수 있기에 중요한 것은 프로젝트 요구사항과 테스트 환경에 맞는 설계를 선택하는 것입니다.
JSON 기반 동적 테스트 설계는 변화와 확장을 효율적으로 처리할 수 있는 설계 방식으로 유지보수성과 확장성이 중요한 테스트 자동화 환경에서 고려해 볼 가치가 충분한 접근법이라 생각합니다.
테스트 자동화에서 가장 중요한 것은 설계가 테스트의 본질에 얼마나 부합하는지라 생각되고 상황에 맞는 최적의 방법론을 선택하는 것이 성공적인 테스트 자동화의 핵심이 아닐까, 지나온 경험과 현재 에이슬립에서 담당 중인 프로덕트를 통해서 깨닫게 된 요즘입니다.