brunch

You can make anything
by writing

C.S.Lewis

by 이지원 Oct 01. 2022

pytest에서 behave로 전환하기

안녕하세요, 클래스팅에서 E2E 테스트 자동화 리드를 맡고 있는 지오입니다. 최근에 WebdriverIO에서 Pytest 전환 후기를 공유했었는데요. 오늘은 Pytest에서 Behave로 전환한 후기를 공유합니다.


결론적으로 사용 언어와 개발 환경이 달라진 점을 제외하곤 WebdriverIO describe/it 구조에서 WebdriverIo Cucumber로 전환했을 때와 크게 다른 점은 없었습니다. 다만 실무에서 여러 차례 자동화 개발 환경 변화를 겪고서 느낀 점은, WebdriverIO가 비교적 최근에 등장한 프레임워크인지라 E2E 테스트 코드 작성에 필요한 API와 그 외 환경 설정이, pytest 및 behave보다 쉽고 편리한 느낌을 받았습니다.

뿐만 아니라 3개월 전 PoC 당시 리서치한 결과를 살펴보면 프론트엔드 진영의 E2E 프레임워크 대부분이 자바스크립트가 메인 언어이고 그중에서 WebdriverIO는 웹과 모바일 모두 지원하기에, 정말 특별한 경우가 아니라면 Javascript 또는 Typescript를 사용하는 WebdriverIO를 추천합니다. 네이티브뿐 아니라 RN 서비스에 특화된 Detox와 같은 그레이 박스 프레임워크도 활용해볼 수 있고, Javascript를 접하다 보면 웹 생태계에 대한 이해도가 함께 높아지기 때문입니다.


다만 Selenium과 Appium 자체를 학습하고 실무에 우선 활용하고 싶다면 Java 또는 python 언어를 베이스로 E2E 자동화에 입문하여 점진적으로 스킬 셋을 넓혀가는 것도 좋은 방법이 될 것 같습니다. 저 같은 경우 E2E 자동화 입문을 WebdriverIO로 하였는데, 결국 WebdriverIO도 Selenium 및 Appium 아키텍처의 영향을 받기 때문에 Selenium과 Appium을 우선 학습 후 WebdriverIO를 다뤘다면 보다 시행착오를 줄일 수 있지 않았을까 생각됩니다.


아무쪼록 python 언어로 pytest와 behave 구축 및 화면 개체 모델 구조로 실무 코드를 작성해보니 WebdriverIO가 정말 편리했구나를 느꼈고, pytest와 behave 구축 간에 몇 가지 삽질을 하게 되었지만, 그만큼 E2E 자동화에 대한 이해도가 높아진 뜻깊은 시간으로 다가왔습니다.


각설하고, pytest에서 behave로 전환한 간단 후기를 시작합니다.


어떤 구조로 구축했나?

pytest로 화면 개체 모델을 기반으로 재사용성을 고려하여 위와 같은 구조로 초기 구축했습니다. 하지만 behave로 구축 간에는 처음부터 많은 것들을 모듈화 시키기보단, 점진적으로 필요에 의해 진행하는 것이 효율적이라는 판단이 들었습니다. 따라서 화면 개체 모델을 기반으로 하되, behave 공식문서에 정의된 구조를 참고하여 구축했고, 경험적으로 꼭 필요했던 클래스만 설계하여 전체적인 구조를 잡게 되었습니다.

behave는 environment.py 모듈을 사용합니다. 이곳에서 테스트 중 특정 이벤트 전후에 실행할 코드를 정의할 수 있습니다. before_step, after_step, before_scenario, after_scenario, before_feature.. 를 정의하여 테스트 전후에 필요한 처리 또는 시나리오 의존성을 코드 레벨로 제거하기 위한 로직을 작성할 수 있습니다. Cucumber와 WebdriverIO에도 당연히 위 역할에 해당하는 기능이 존재합니다.

features 디렉토리에는 data.py가 있는데요. 이곳에서 테스트에 필요한 데이터들을 중첩 딕셔너리로 관리하여 BasePage 클래스에 정의된 input 함수에 element.send_keys에 필요한 text 값으로 넘겨줘서 사용할 예정입니다. 예시는 위 코드를 참고해주세요.

BasePage 클래스의 목적은 테스트 시나리오에 필요한 로케이터 핸들링 함수를 정의하여 쉽게 사용하기 위함입니다. 예를 들어 find_element 함수는 리턴 값이 self.driver.find_element(by=locator [0], value=locator [1])인데요.

selenium webdriver에 정의된 내부 값을 살펴보면 위와 같이 정의되어 있습니다. 해당 값들을 참고해서 재사용할 find_element 함수를 설계하고, 이를 다른 함수에서 계속 활용하여 쉽고 편리하게 테스트 코드를 작성할 수 있습니다.


우선 꼭 필요해 보이는 것들만 정의를 해뒀고 추후 리팩토링 간에 BasePage 클래스에는 테스트 코드 작성을 도와주는 다양한 함수들이 설계될 예정입니다.


Pages의 login_email.py

위와 같은 구조로 클래스팅 시나리오 구현에 필요한 로케이터가 담긴 데이터 파일을 별도로 정의할까 고민해봤지만 유지보수와 가독성이 떨어질 것 같아 고민 끝에 조금 다른 구조를 택했습니다.


로케이터 같은 경우는 각 페이지에 해당하는 로케이터를 각각의 페이지 클래스 상단에 작성하여 관리합니다. 테스트 데이터는 하드 코딩하지 않고 data.py에 정의된 딕셔너리 값을 활용합니다.


기본적인 흐름은 BasePage 클래스에 정의된 함수들을 각 Page에서 활용하여 시나리오 구현에 필요한 동작을 각 페이지에서 설계하는 방식입니다.

예를 들면 LoginEmail 클래스에서는 BasePage 클래스에 정의된 함수들을 사용해서 시나리오 구현에 필요한 동작을 설계합니다. 각 페이지에 해당되는 로케이터는 위 예시처럼 각 클래스 안에 작성합니다.


위와 같은 형태로 테스트에 필요한 모든 화면을 클래스로 정의하고, BasePage에 설계된 엘리먼트 핸들링 함수를 기반으로 각 페이지에서 필요한 동작을 함수로 구현하여 steps.py에서 활용합니다.

features 디렉토리에는 데일리 테스트 케이스를 뜻하는 데일리 디렉토리를 만들고, 데일리 케이스에 해당하는 feature를 작성합니다. 테스트를 어떻게 그룹화시킬지는 각 조직의 자동화 엔지니어가 판단해서 진행하는 것이 효율적입니다. 회사마다 다르고 정답은 없지만, 병렬 테스트 진행 간에 시나리오 의존성 문제는 어떻게 제거할 것이며 어떤 식으로 그룹화시켜야 코드 레벨에서 자동화 유지보수가 편리할지에 대한 고민은 필요합니다.

steps.py에는 feature 파일의 각 단계에 해당하는 코드를 작성합니다. 추후 behave에서 지원하는 시나리오 개요 및 백그라운드와 같은 기능을 통해 중복을 제거하고 behave에서 추구하는 BDD 방향으로 리팩토링 예정입니다.


리팩토링 시점은 전체 시나리오 구현 후 서비스 운영 레벨에서 코드 레벨에서의 문제가 없음이 보장될 때입니다. 실무는 빠른 구현이 우선이고 리팩토링에 너무 많은 시간을 쏟지 않아야 한다고 생각합니다. 테스트 자동화 코드 리팩 링에 너무 많은 시간을 쏟지 않으려면 일단 전체를 구현하고 동작을 확인한 다음, 중복되는 요소와 불필요한 코드를 수정하는 것이 효율적이라 판단됩니다. QA 사이드에서 구현해야 하는 테스트 커버리지는 가변적이지 않고 정해져 있기 때문입니다.


pytest에서 behave로 전환한 과정을 간단히 살펴보았습니다. WebdriverIO에서 Cucumber로, Cucumber에서 Pytest로, Pytest에서 Behave로 전환하며 초기 구축부터 유지보수까지 진행하며 느낀 점은, 실무 DeepDive를 하기 위해선 사용 중인 프레임워크의 공식 문서를 읽을 줄 알아야 하고, 오픈소스 코드를 분석하기 위한 엔지니어로서의 기초 체력이 필요했습니다.


엔지니어로서 기본기가 갖춰지지 않은 상태에서 시도하는 E2E 자동화 테스트는 필연적으로 수많은 문제에 직면하게 되고 수많은 문제를 해결할 기본기를 갖추지 않는다면 자동화의 방향은 점차 희미해지고 끝내 길을 잃게 되지 않을까 싶습니다.


실무가 어느 정도 안정화되면 E2E 자동화 관련된 온라인 또는 오프라인 강의형 스터디를 진행하여 저의 경험을 많은 분들께 나눠주고 싶습니다. E2E 자동화에 관심 있는 QA 엔지니어분들과 소통하며 유의미한 활동과 커뮤니티가 시작되길 바라봅니다.


고맙습니다.


이지원 드림.

매거진의 이전글 [소프트웨어 테스팅] 마지막화
브런치는 최신 브라우저에 최적화 되어있습니다. IE chrome safari