좋은 테스트 코드
Java, Python 기반의 테스트 자동화 환경과 더불어 Selenium과 Appium을 High Level로 추상화시킨 다양한 테스트 프레임워크를 경험하면서 어느덧 SDK Product 검증을 위해 Node.js 기반의 WebdriverIO를 활용하게 되었습니다.
테스트 러너는 WebdriverIO를 사용하되 테스트 프레임워크를 Cucumber에서 Mocha 기반으로 마이그레이션 중 당연하다는 듯이 E2E 테스트 코드의 추상화를 점차 지양하게 되는 모습을 발견하게 되었는데요.
E2E 테스트 코드의 추상화를 지양하는 이유에 대해 경험에서 비롯된 생각을 공유해보려 합니다.
페이지 요소를 캡슐화하고 테스트 코드에서 직접 로케이터를 사용하지 않도록 구조화하는 전형적인 Page Object Pattern을 활용하고 있지만, 추상화를 통해 관리하고 있지는 않습니다. 각 it 블록마다 100줄 이상의 테스트 로직이 포함될 수 있지만, 이러한 방식을 선택한 이유는 테스트 흐름을 직관적으로 표현하기 위함입니다.
E2E 테스트 코드에서 추상화를 어느 정도까지 할 것인가는 항상 고민되는 부분입니다. 중복을 줄이기 위해 추상화를 과도하게 하면 테스트 흐름이 보이지 않아 디버깅이 어려워지고, 반대로 그대로 두면 코드가 길어져 유지보수가 힘들어지는 딜레마가 발생합니다.
그동안 다양한 테스트 환경에서 경험한 바에 따르면, 특히 웹과 모바일 UI 테스트에서는 테스트 케이스를 읽는 사람이 앱이 어떤 순서로 동작하는지 쉽게 파악할 수 있도록 테스트 흐름이 한눈에 보이는 것이 더욱 중요하다고 느꼈습니다. 과도한 추상화는 특정 메서드 내부에서 여러 동작을 캡슐화하면서 테스트 코드 자체만 봐서는 실제 UI 상에서 어떤 흐름이 발생하는지 보이지 않게 만들기 때문입니다.
추상화의 장점도 있지만, UI 테스트의 핵심 목표는 UI 흐름이 올바르게 작동하는지를 확인하는 것이므로 테스트 코드에서 시나리오가 명확하게 드러나도록 하는 것이 효과적인 경우가 많았습니다.
추상화의 장점도 분명히 존재합니다. 그러나 UI 테스트의 핵심 목표는 UI 흐름이 올바르게 작동하는지를 확인하는 것이라는 점에서, 테스트 코드가 너무 복잡하게 숨겨지지 않도록 하는 것이 중요합니다. 테스트 코드가 시나리오와 흐름을 명확하게 드러낼 수 있도록 작성하는 것이 더 효과적인 경우가 많습니다. 즉, 테스트 코드가 복잡해져도 UI 흐름이 직관적으로 보이게 유지하는 것이 우선입니다.
추상화를 줄이면 코드가 길어지는 문제는 피할 수 없습니다. 그러나 그렇다고 해서 UI 테스트 코드의 유지보수가 어려워지는 것은 아닙니다. 중요한 것은 디자인 패턴을 활용하여 페이지 요소와 로케이터를 캡슐화하고, 테스트 코드 내에서 UI 요소를 조작하는 부분은 페이지 객체를 통해 관리하도록 하는 것입니다. 이렇게 하면 테스트 흐름을 직관적으로 유지하면서도, 로케이터 관리가 한 곳에서 이루어져 유지보수성을 높일 수 있습니다.
UI 테스트 코드에서 추상화는 필요하지만, 그 목적이 "중복을 줄이는 것"보다는 "테스트 흐름을 직관적으로 유지하는 것"에 초점을 맞춰야 한다고 생각합니다. 지나친 추상화는 오히려 테스트 흐름을 흐릿하게 만들고 디버깅을 어렵게 하는 요인이 될 수 있습니다.
중복을 줄이려고 지나치게 추상화하지 않고, 테스트 흐름이 한눈에 보이도록 직관적으로 작성하면서도, UI 요소와 로케이터를 캡슐화하여 로직은 테스트 코드에서 명시적으로 나타내되, UI 요소 관리는 분리하는 방식이 E2E 테스트 코드에서 가독성과 유지보수성을 모두 적절하게 확보할 수 있는 최적의 구조라고 생각합니다.