안녕하세요. 스포카 QA Leader 염주일입니다.

스포카 QA 팀에서 오픈소스 자동화 도구인 Appium을 사용하여 Mobile App 테스트 자동화의 첫발을 내디뎠습니다.

지금까지의 테스트 자동화 구축 과정에 관해 이야기해볼까 합니다.

테스트 자동화를 구축하려는 이유가 무엇인가요?

보통 아래와 같은 이점을 얻기 위해 테스트 자동화를 구축하려 하죠.

  • 테스트 커버리지 확대
  • 테스트 일관성과 신뢰성 확보
  • 테스트 비용 절감 및 기간 단축

테스트 자동화 구축과 컨설팅을 전문적으로 수행하는 업체들의 일관된 광고 토픽이기도 한데요.
일정 수준의 커버리지가 확보된, 일관되고 신뢰할 수 있는 테스트를 효율적으로 수행할 수 있는 이점이 있다고 볼 수 있겠습니다.

이것만 보면 테스트 자동화를 하지 않을 이유가 없군요!
하지만, 단점도 있습니다. 한번 볼까요?

  • 제한적인 검증 케이스
  • 발견되는 버그가 많지 않음
  • 테스트 자동화 구축 및 유지보수 비용 증가

뭐지?

테스트 자동화의 장점이 단점에 의해 일부 상쇄되는군요!

왜 그럴까요?

장점을 기준으로 현실적인 이야기를 해 볼게요.
먼저 테스트 커버리지 확대는 일부 맞는 말이긴 해요. 다만, 자동화만으로는 여러 가지 이유로 달성하기 힘들죠. 특히, 엣지 케이스와 일부 네거티브 테스트 케이스는 자동화로 구현하기가 상당히 어렵습니다. 비용도 많이 들고요.

테스트 자동화는 테스트 커버리지를 늘리는데 보조재 역할을 한다고 볼 수 있어요. 테스트 범위의 일정 부분이 자동으로 수행되면서, 테스트 엔지니어가 다양한 테스트를 할 수 있는 시간을 벌어주죠. 테스트 커버리지 확대의 주체가 테스트 엔지니어이긴 한데요, 결과적으로 자동화의 도움으로 커버리지가 늘어난다고 볼 수 있겠네요.

다음 테스트의 일관성과 신뢰성을 확보하는 것 역시 맞는 말입니다. 테스트 엔지니어의 컨디션에 따라 달라지는 테스팅의 품질을 걱정할 필요가 없죠.

다만, 테스트 조건의 다양성을 갖추지 않고 일반적인 소프트웨어 테스트, 즉 버그를 찾기 위한 테스트를 수행하는 관점으로 자동화를 활용하고자 한다면, 일관성과 신뢰성이 무가치하게 느껴질 정도로 테스트 자동화의 유효성을 찾지 못하게 될 수 있습니다.

여러 구축 사례에서 볼 수 있을 것 같은데요. 어렵게 테스트 자동화를 구축했지만, 이것을 통해 새로운 버그를 찾지 못하는 것에 실망하는 글들을 웹상에서 종종 볼 수 있습니다.

이런 현상은 테스트 조건을 적절하게 변경하고 유지보수하지 않아 발생하는 것으로 볼 수 있을 것 같아요.

일종의 살충제 패러독스를 겪게 되는 겁니다. 이런 이유로 “고정된 조건의 테스트 자동화는 테스팅이라고 볼 수 없다”고 이야기하시는 분들도 있습니다.

하지만, 이 부분은 약간 논란의 여지가 있다고 생각됩니다. “사전 정의된 테스트 단계를 실행하고, 실제 결과를 예상된 결과와 비교하는 것” 자체로 범위를 규정하고 활용한다면 충분히 가치가 있다고 생각해요. 리그레션 테스트가 이 범주에 속하죠.

마지막으로 테스트 비용 절감 부분은 테스트 자동화 적용 분야에 따라 다름이 있습니다만, 대체로 구축 및 유지보수 비용과 Trade off 된다고 보면 될 것 같아요.

우리에게 필요할까요?

테스트 자동화의 활용 목적을 명확히 하고, 위의 장점을 최대화할 방법이 있다면 하지 않을 이유는 없죠! 특히, 적절한 범위의 리그레션 테스트에 활용한다면, 비단 테스트 효율을 높이는 것뿐만 아니라 우리가 지향하는 Agile 프로세스에도 많은 도움이 될 것으로 생각합니다.

대규모 개발 또는 MVP 개발, 하물며 아주 작은 기능을 개발하여 그 산출물을 배포할 때까지의 사이클은 기본적으로 “기획 - 디자인 - 개발 - 테스트” 입니다. 전통적인 구조적 방법론처럼 보이지만 아무리 Agile이라고 해도 (병렬 수행으로 거의 동시에 진행될 수는 있지만) 프로젝트 내 활동을 기능적으로 나눈다면 이 범주를 벗어날 수는 없죠.

여기서 기획-디자인-개발을 아무리 빠르게 진행한다고 해도 우리가 일정 수준의 품질을 유지하고, 그것에 대한 Confidence를 갖기 위해서는 테스트 기간을 줄이기 쉽지 않습니다. 특히, 추가되거나 변경에 의한 영향이 없는지 확인하는 절차를 제외 할 수 없습니다. 리그레션 테스트를 할 수 있는 최소한의 시간이 필요한 거죠.

결국 이 리그레션 테스트때문에 아주 작은 기능을 추가하더라도 스프린트 또는 이터레이션의 기간은 일정 시간 이하로 떨어지지 않습니다.

이것이 우리가 지향하는 Agility의 발목을 잡을 수 있다고 생각해요. 게다가 이 리그레션 테스트의 양은 제품이 배포되는 횟수에 따라 계속해서 늘어나는 경향이 있죠.

이것을 완전히 해소해 줄 수는 없지만(비용의 문제로..), 상당 부분 보완을 해 줄 수 있는 솔루션이 이 테스트 자동화라고 생각합니다.

그래서 우리는?

앞서 살펴본 장점과 단점을 고려하여 테스트 자동화의 활용 목적과 범위를 아래 세 가지로 잡았습니다.

  1. 리그레션 테스트에 활용하자.
  2. 그 범위는 구축과 유지보수에 부담되지 않는 수준으로 하자. (현재 테스트 케이스의 30% 수준)
  3. All Pass 시나리오에 기반한 Positive 테스트 케이스를 자동화의 대상으로 추출해서 진행하자.

이렇게 테스트 자동화의 목적과 범위를 결정 후 적당한 자동화 도구룰 선정하기로 했어요.

어떤 도구를 사용할까?

도구를 선정하기 전에 우리가 어떠한 관점으로 테스트를 수행할지 정해야 합니다. Use Case Flow에 따른 UI 기능 테스트를 할 것인지, 아니면 명세표의 Life cycle에 따라 데이터의 변화 과정을 체크할 것인지, 그것도 아니면 둘 다 만족하는 테스트 환경을 구축할 것 인지를 정해야 하는거죠.

먼저 우리는 활용 목적과 범위를 정했으니 그것을 기준으로 효율이 높은 쪽을 선택했습니다. Use Case에 따른 기능과 UI 변화를 체크하는 것이 상대적으로 효율이 높다고 판단했어요. 게다가 이쪽 부분이 사용자 접점이 가장 많은 부분이기도 하죠.

이렇게 방향을 잡고 아래의 사항을 만족하는 UI 자동화 도구가 어떤 것이 있는지 조사했어요.

  1. Android, iOS 모두 지원할 것
  2. 오픈소스이어야 할 것
  3. 스크립팅에 다양한 언어를 지원해야 할 것
  4. 다른 도구와의 통합이 가능할 것

아래 표와 같이 Appium이 오픈소스임에도 불구하고 많은 사항을 충족시켜주네요!

tools

네, 테스트 자동화 도구로 Appium을 사용하기로 결정하고 환경 구축을 시작했습니다.

Appium 환경 구축하기

Appium 환경 구축은 웹 상에 많은 가이드와 레퍼런스가 있음에도 불구하고 QA 엔지니어가 구축하기엔 여간 까다로운 일이 아닙니다. 특히 iOS 테스트 환경 구축은 더욱 그러하죠.

Mac에서 Android, iOS 앱을 테스트 할 수 있는 환경을 만드는데 필요한 과정을 간단하게 나열하자면…

[Android 환경]

  1. 디바이스 또는 에뮬레이터 연결을 위한 JDK와 Android Studio 설치
  2. Appium Server 사용을 위한 Node.js 세팅
  3. Appium Server 및 Inspector 세팅

비교적 간단하죠.

[iOS 환경]

  1. WebDriverAgent 빌드를 위한 Xcode 설치
  2. 환경 구축에 필요한 라이브러리 설치를 위해 Homebrew 세팅
  3. Appium Server 사용을 위한 Node.js 세팅
  4. Appium Server 및 Inspector 세팅
  5. iOS 디바이스와 통신하기 위한 libimobiledevice 라이브러리 설치
  6. 동적 라이브러리 관리 도구인 Carthage 설치
  7. Command line으로 iOS 앱을 설치할 수 있게 도와주는 ios-deploy 세팅
  8. 디바이스를 제어하기 위한 WebDriverAgent 빌드

그밖에 세세하게 세팅해야 하는 부분이 있습니다. 복잡하네요.

플랫폼 별 Appium 환경 구축에 대한 상세는 다른 기술 문서를 통해 이야기할게요.

Appium 동작 방식

Appium이 어떻게 동작되는지 간단하게 살펴 보겠습니다.

<출처 : https://www.pentalog.com/blog/mobile-development/mobile-automation-with-robot-framework-and-appium>



Appium Server는 Node.js를 사용하여 작성된 HTTP 서버입니다. Appium Client와 JSON Wire 프로토콜 및 HTTP 프로토콜을 사용하여 통신을 하죠. 또, Appium Server는 일종의 연결 Config인 DesiredCapabilites 정보를 사용하여 테스트 디바이스와 연결합니다.

연결된 테스트 디바이스를 제어하는데에는 각 플랫폼 벤더에서 제공하거나 해당 플랫폼에 특화된 자동화 프레임워크를 이용합니다. 안드로이드 경우 UIAutomator2, iOS는 XCUITest 프레임워크를 사용하죠.

Appium은 각 플랫폼의 테스트 프레임워크에 명령을 전달하고, UIAutomator2 또는 XCUITest는 해당 명령을 받아 테스트 디바이스를 컨트롤하죠.

테스트가 완료되면 결과가 Appium 서버에 전달되고, 서버는 해당 log를 클라이언트에 전달하는 방식으로 테스트가 진행됩니다.

Appium Inspector 활용하기

Appium을 구성하는 것들 중 Server만큼 중요하고 유용한 친구가 있어요. 바로 Appium Inspector죠.

Appium Inspector는 테스트하려는 앱 화면의 Element를 식별해주거나, 앱 화면을 DOM 구조로 파싱해주는 역할을 해요.

테스트 자동화는 테스트 대상이 되는 객체에 대한 정보를 식별하는 것이 중요한데요. 이 Inspector가 그 역할을 해줍니다. 테스트 스크립트를 개발하는데 없어서 안되는 도구이죠. 그리고, 부가적으로 레코딩과 일부 동작의 스크립팅도 제공해주는 착한 친구입니다.

Appium Inspector와의 연결은 테스트 디바이스 연결 방식과 같이 DesiredCapabilities 정보에 의해 이루어집니다. 이 컨피그 정보는 종류가 다양한데요. Appium 홈페이지에서 제공하는 Appium 가이드를 참고하여 컨피그를 설정하고 Appium Server를 띄운 후 실행하면 아래와 같은 화면이 출력됩니다.

appium-inspector

Capability 설정에 따라 테스트 디바이스에서 앱이 실행되고, 앱 화면이 미러링됩니다.

앱 화면의 구조도 DOM Tree 형태로 노출되네요. 앱 화면이 미러링된 창의 특정 부분을 클릭하면 해당 Element의 정보를 알 수 있습니다.

이 Inspector로 식별된 Element 정보는 앞서 이야기 했듯이 테스트 스크립트 개발에 필요한 중요하고 기본적인 정보입니다. 여기어 노출되는 ID, XPath 등의 정보로 Element 타게팅 방법을 적절하게 활용하여 테스트하려는 객체의 노출 여부를 확인하고, 클릭 후 변화된 화면을 식별하고, 정보를 입력하면서 테스트를 수행합니다.

테스트 케이스 정제

지금까지 테스트 자동화 구축 전략을 세우고, 우리 입맛에 맞는 도구를 고른 후 환경 세팅까지 마쳤습니다. 이제 테스트 스크립트를 개발하는 일만 남았는데요. 그 전에 중요한 과정을 거쳐야 합니다.

테스트 스크립트의 기반이 되는 테스트 케이스가 자동화하는데 적합하게 구성되어 있는지 분석할 필요가 있어요. 필요하다면 테스트 케이스를 수정/삭제/추가 해야 합니다. 그리고, 이 테스트 케이스 적합도 분석과 정제는 테스트 자동화의 유효성과 유지보수성을 결정하는 중요한 과정이기도 합니다.

앞서 정한 활용 범위와 커버리지, 그리고 테스트 자동화 도구의 특성에 따라 테스트 케이스를 추출하고 정제했어요. 현재의 테스트 케이스에서 Positive 테스트 케이스를 추출하고, 다중 예상 결과에 대한 분리 작업, 동적인 객체 확인 제거 등등의 정제 과정을 거쳤습니다.

다행히 현재 테스트 케이스는 카테고리를 명확하게 나누어 관리되고 있고, 사전조건, 절차, 예상결과가 명확한 상태이며, n:1구조를 가진 케이스는 없었기에 구조 변경까지는 필요 없었어요.

테스트 케이스 적합도 분석과 정제를 통해 우리 목표치와 같이 전체 테스트 케이스 중 약 30% 케이스를 선정하고, 우선순위를 부여하여 1차와 2차 나누어 테스트 스크립트를 개발하기로 했습니다.

테스트 스크립트 개발

테스트 스크립트는 Python으로 구현하기로 했어요.

안드로이드 앱 테스트 자동화를 먼저 진행하기로 했고, 1차로 전체 테스트 케이스의 약 10%의 커버리지를 목표로 진행했습니다. Sprint를 운영했는데, 정비 버전 통합 테스트 기간과 겹쳐 일정이 계획보다 약 2주 Delay 되었어요.

burndown

1차로 진행된 스프린트 번다운 입니다. 이상적이지는 않지만, 많은 프로젝트에서 볼 수 있는 그림이 되었어요.

스프린트 중간 중간에 제품팀 개발자 분들께서 많은 도움을 주셨습니다. 바쁜 와중에 도움을 주신 제품팀 개발자 분들께 감사의 말씀 드립니다.

현재까지 개발된 테스트 구조는 아래와 같아요.

test-struc

간단하게 설명을 하자면, Python의 Unittest 라이브러리를 활용하여 Appium Client Test Set을 구성했어요.

기본적인 구조는 AndroidTestRun에서 기능별 테스트 케이스를 Suite로 묶어 UnittestRunner를 통해 테스트가 수행될 수 있게 구성했습니다.

홈, 더보기, 검색, KAMIS, 거래처 찾기 카테고리의 테스트 케이스 Set을 Unittest의 TestLoader로 로딩해서 실행하게 되면 아래와 같은 순서로 반복되는 구조에요.

  1. 테스트 setUp() - ConfigSet 클래스의 testConfig() 호출
  2. 준비된 Testcase 실행
  3. tearDown()으로 테스트 종료 및 자원 해제
  4. AndroidTestRun에서 지정된 카테고리별로 1~4항목 반복

테스트 결과는 Appium Client 콘솔에 log 형태로 뿌려지기 때문에 결과 문서를 따로 추출할 수가 없습니다. 해서 HtmlTestRunner 라이브러리를 사용하여 Html로 결과를 뽑기로 했어요. 아래와 같이요.

result-html

위의 결과서에서 Error나 Fail 항목 등은 View 버튼을 통해서 로그를 확인할 수 있습니다.

현재는 Android App 테스트 케이스의 약 10%의 커버리지를 확보해 놓은 상태입니다만, 2022년 3분기까지 Android / iOS App 각각 테스트 케이스의 약 30% 커버리지를 확보할 계획이에요. Backoffice 역시 전체 테스트 케이스의 약 30% 커버리지를 목표로 Selenium을 활용하여 구축할 예정입니다.

마무리

지금까지 구축과정에 대해 말씀드렸습니다. 앞서 말씀드린 그것처럼 테스트 자동화는 소프트웨어에 대한 다양한 테스트를 효율적으로 할 수 있는 만능 일꾼은 아닙니다. 필요한 부분에 필요한 만큼만 지원해주는 서포터라고 볼 수 있죠. 자동화가 꼭 필요한지도 살펴보아야 합니다. 어떤 목적으로 테스트 자동화를 활용할 것인지 명확해야 하고, 그 목적에 따라 전략을 잘 마련해야 유용하게 활용할 수 있다고 생각해요.

우리는 테스트 자동화가 왜 필요한지와 어떻게 활용할 것인지, 자동화의 장점을 최대화할 방안이 무엇인지 고민을 통해 테스트 자동화를 구축하고 이제 한 걸음 뗐습니다.

이 테스트 자동화가 우리 제품의 품질에 대한 Confidence를 확보하는 데 일조하고, 우리가 지향하는 프로세스에도 도움이 되는 아주 유용한 친구로 자리 잡는 것을 기대해 봅니다.

스포카에서는 “식자재 시장을 디지털화한다” 라는 슬로건 아래, 매장과 식자재 유통사에 도움되는 여러 솔루션들을 개발하고 있습니다.
더 나은 제품으로 세상을 바꾸는 성장의 과정에 동참 하실 분들은 채용 정보 페이지를 확인해주세요!