brunch

You can make anything
by writing

C.S.Lewis

by Ruth Hyojin Nam Feb 20. 2024

[앱자동화(3)](for Mac) appium 자동화


1. 코드 작성 전 

1-1. Appium Server GUI 실행중인 상태

1-2. Android Studio에서 가상 디바이스(안드로이드 애뮬레이터)를 실행 → 테스트 할 어플리케이션을 선택 (예시로, Google Calendar를 실행)

1-3. Android Inspector 실행 (Host / Port / Path / Desired Capabilities 세팅된 상태) → Session Start → Android Inspector 좌측 화면에 Android Studio에서 실행중인 휴대폰 화면이 미러링되어 노출되는 것이 확인된다. 

        혹은, 1-2 전 Android Inspector가 이미 실행 중이었다면 1-2 실행 후 Android Inspector의 [Refresh Source And Screenshot] 버튼을 클릭한다.

             ※ 실물 디바이스를 사용하는 경우에도 진행 순서는 동일함

             실물 디바이스에서 테스트 할 어플리케이션 선택 → Android Inspector 실행 → Session Start → Android Inspector 좌측 화면에 실행중인 휴대폰 화면이 미러링되어 노출되는 것이 확인된다. 


1-4. Android Inspector 의 휴대폰 화면에서 특정 메뉴를 클릭하면 App의 Source와 Select Elements 영역에서 선택한 부분의 element 정보가 노출된다. appium 자동화 코드 작성을 위해 사용되는 elements 정보는 id와 xpath를 사용한다. 


2. appPackage, appActivity 확인 

스마트폰에 설치되어있는 어플을 실행시켜 AppPackage와 AppActivity를 알아보겠습니다.

스마트폰에서 앱을 실행해놓은 상태로 두고 기기를 mac으로 USB 연결합니다.

위 상태에서 아래의 커맨드를 터미널에서 실행합니다.


[방법 1.] terminal 실행 → 아래 명령어 입력 후 엔터 시 appPackage name과 appActivity name이 확인된다.

> aapt dump badging ‘apk 파일명’


ex) /Users/**user name**/Library/Android/sdk/build-tools/버전숫자/aapt dump badging APK파일명

    → [예시] /Users/**user name**/Library/Android/sdk/build-tools/34.0.0/aapt dump badging /Users/Android/data/example.apk


appPackage package: name= ****    ---> appPackage 명 appActivity launchable-activity: name : *****  ---> appActivity 명


[방법 2.] terminal 실행 → 아래 명령어 입력 후 엔터

adb shell dumpsys window | grep -E 'mCurrentFocus'


※ 참고

위 명령어 입력 후 'adb: more than one device/emulator' 메시지가 나온다면 디버그 모드로 변환 할 디바이스가 1개 이상이기때문이다. (아래 이미지 처럼 device와 emulator 두개가 확인됨)

그럼 아래와 같이 디버그 모드로 변환할 디바이스를 선택 후 커맨드 해야합니다. 

adb -s **adb device name** shell


** adb device name**은 위에서 확인한 adb device name으로 입력해줍니다. 

예시) 제가 가진 디바이스의 id를 입력해본다면 아래와 같이 입력 후 엔터해주면 됩니다.

adb -s e2cc6a13 shell


특정 디바이스의 name을 입력해서 해당 디바이스의 shell을 실행합니다.

그러면 c2q:/$ 또는 astarqlteskt:/ $ 라고 프롬프트가 표시됩니다. 


이 상태에서 위의 adb shell 명령어를 다시 입력하면 되는데, 이 상태는 이미 shell을 입력한 상태이기 때문에 커맨드 앞의 adb shell 부분을 제외하고 아래와 같이 입력 후 엔터하면 appActivity 정보가 노출됩니다. 

dumpsys window | grep -E 'mCurrentFocus'

⇢ [결과] mCurrentFocus의 값 중 '/' 을 기준으로 왼쪽이 AppPackage, 오른쪽이 AppActivity 입니다.

               (예시를 위해 사용한 apk는 네이버 앱이며 AppPackage는 com.nhn.android.search / appActivity는 com.nhn.android.search.universe.UniverseActivity 입니다.)


그럼, 이렇게 확인된 정보를 가지고 Android Inspector → Desired Capabilities 에 내용을 입력하여 네이버앱을 자동으로 실행해보겠습니다. 



※ 참고

이때 발생될 수 있는 에러가 있습니다. 

"Failed to create session. An unknown server-side error occurred while processing the command. 

Original error: Cannot start the 'com.nhn.android.search' application. 

Original error: Error executing adbExec. Original error: 'Command '/Users/**user name**/Library/Android/sdk/platform-tools/adb -P 5037 -s e2cc6a13 shell am start -W -n com.nhn.android.search/com.nhn.android.search.universe.UniverseActivity -S -a android.intent.action.MAIN -c android.intent.category.LAUNCHER -f 0x10200000' exited with code 255'; Command output: Security exception: Permission Denial: starting Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10200000 cmp=com.nhn.android.search/.universe.UniverseActivity }.."


이 에러가 발생될 수 있는 경우는 

해당 애플리케이션 제조업체에서 자동화 사용을 허용하지 않도록 설정한 경우 입니다. 

이 때 보안 예외로 피하거나 개발자옵션에 해당하는 옵션이 없다면 appium에서 허용하지 않은 동작을 피하기 위해appium:ignoreHiddenApiPolicyError를 true로 설정 & noReset:true로 설정하여 appium이 수행 할 수있는 작업을 할 수 있도록 해줍니다. 

appium inspector의 desired capabilities에서 두가지 옵션 추가


3. 자동화 코드 작성 방법

Android Inspector 에서 확인한 id 또는 xpath를 이용하여 파이썬 코드를 작성하여 자동화 할 수 있습니다. 

(1) Pycharm을 실행하고 새로운 프로젝트를 생성합니다. 

(2) Pycharm 우측 상단 Setting 메뉴 'Reference - Project:생성시 작성한 프로젝트 명 - python Interpreter'로 이동해서 "Appium-Python-Client"를 install 합니다. 

(3) 새로운 Python 파일을 만듭니다. 

(4) Android Inspector 의 JSON 값을 붙여넣기 합니다. 

(5) webdriver를 인스턴스로 만들고 실행하면 Android Inspector에서 세션을 연결한 것과 동일하게 실행되는 것을 확인할 수 있습니다. 

(6) 이 후 코드는 테스트 스위트에 맞게 action으로 작성하고 결과값을 검증하도록 작성해주면 됩니다. 


[자동화 코드 예시]

자동화 코드 작성에 어려움이 있는 경우 Github에 등록된 예시나 오픈 소스를 활용하는 것도 하나의 방법이 될 수 있습니다. 

예시 - Appium Pro에서 제공하는 코드 예시 

예시들을 참고하여 자동화 스크립트를 작성해보도록 합니다. 



4. TIP

[1] 자동화 코드를 실행할 때  Appium 서버를 일일이 실행시키거나 별도로 띄워놓지 않아도 자동으로 서버를 사용해주는 코드를 추가해주면 용이하게 사용할 수 있습니다. 


[2] 자동화 실행 중 앱이 실행되지마자 종료되거나 에러가 발생되는 경우(ex) Unclose Socket, Already use in port 에러) 연결된 기기를 uninstall하고 재 연결 합니다. 


[3] Appium 병렬로 실행하기

Appium 서버를 각각 띄워서 병렬로 실행하는 방법 외에 자동화 코드에 cap 설정을 통해 병렬 실행을 할 수 있습니다. 

{appium에서 제공하는 가이드 링크 : https://appiumpro.com/editions/28-running-multiple-appium-tests-in-parallel}




            클라이언트 병렬화          

JAVA로 자동화 코드 작성시 Maven과 Surefire 플러그인을 pom.xml 사용하는 방법

처리할 수 있는 Appium 세션수에 일치하도록 메소드나 클래스와 같은 그룹화를 기반으로 테스트 스레드 수를 지정 할 수 있습니다. 


서버 병렬화          

서로 다른 포트에서 수신 대기하는 서로 다른 Appium 서버를 시작하도록 처리합니다. 


이 후 각 테스트 스레드에 적절한 포트를 포함하도록 Appium 서버의 URL을 조정합니다. 


            실행 중인 단일 Appium 서버에서 여러 세션을 시작하기          

앞서 살펴본 것처럼 동시에 여러 테스트를 실행하도록 클라이언트를 설정하고, 여러 세션을 처리 할 수 있도록 Appium 서버를 실행하는 것(Appium pro에서 사용 중인 Gradle 설정에서는 위에 설명한 방법을 사용할 수 없습니다.) 외에 간단한 병렬화 방식으로 테스트 클래스를 기반으로 병렬화 할 수 있습니다. 


다음으로 다양한 클래스에 원하는 기능의 다양한 세트가 포함되도록 테스트 스위트를 구성합니다. 


[iOS 시뮬레이터에서 병렬로 실행할 수 있는 로그인 테스트 예시 코드]




예시의 두가지 클래스는 몇가지 기능만 다릅니다. 이제 Gradle을 사용하여 테스트를 병렬로 실행 할 수 있습니다. 


이것을 실행하면 Appium 서버가 동시에 여러 세션을 처리하고 로그를 출력하는 것을 볼 수 있습니다. 

IOS 코드 예시 외에 안드로이드 테스트 클래스의 코드 샘플도 참고하세요. 



추가로, 병렬 실행 시 서로 다른 테스트 세션 간 시스템 리소스 충돌이 발생하지 않도록 아래 기능을 포함해야 함을 참고하시기 바랍니다.


       Android 병렬 테스트 기능

                                          udid: 이 기능을 포함하지 않으면 드라이버는 ADB에서 반환한 목록의 첫 번째 장치를 사용하려고 시도합니다. 이로 인해 동일한 장치를 대상으로 하는 여러 세션이 발생할 수 있으며 이는 바람직하지 않은 상황입니다. udid따라서 테스트를 위해 에뮬레이터를 사용하는 경우에도(이 경우 에뮬레이터는 다음과 같습니다) 기능을 사용하는 것이 중요합니다 emulator-55xx. 

 systemPort: UiAutomator2 프로세스와 통신하기 위해 Appium은 호스트 시스템과 장치에서 포트를 여는 HTTP 연결을 활용합니다. 호스트 시스템의 포트는 단일 세션용으로 예약되어야 합니다. 즉, 동일한 호스트에서 여러 세션을 실행하는 경우 여기에서 서로 다른 포트를 지정해야 합니다(예: 8200하나의 테스트 스레드와 8201다른 테스트 스레드에 대해). 

 chromeDriverPort: 마찬가지로, WebView 또는 Chrome 테스트를 수행하는 경우 Appium은 고유한 포트에서 고유한 Chromedriver 인스턴스를 실행해야 합니다. 이러한 종류의 테스트에서 포트 충돌이 발생하지 않도록 하려면 이 기능을 사용하십시오.                                    


       iOS 병렬 테스트 기능

                                          udid: Android와 마찬가지로 동일한 기기에서 세션을 실행하지 않도록 특정 기기 ID를 지정해야 합니다. 시뮬레이터의 경우 udids를 실행하여 찾을 수 있습니다 xcrun simctl list devices. 실제로 시뮬레이터 테스트를 수행하는 경우 해당 기능 udid이 필요하거나 및deviceName 기능 의 고유한 조합이 platformVersion필요하다고 말했어야 합니다 . 아래를 참조하세요... 

deviceName및 platformVersion: 장치 이름과 플랫폼 버전의 고유한 조합을 지정하는 경우 Appium은 요구 사항에 맞는 고유한 시뮬레이터를 찾을 수 있으며 이 경우 udid를 지정할 필요가 없습니다. 

wdaLocalPort: UiAutomator2와 마찬가지로 iOS XCUITest 드라이버는 특정 포트를 사용하여 iOS 장치에서 실행되는 WebDriverAgent와 통신합니다. 이것이 각 테스트 스레드마다 고유한지 확인하는 것이 좋습니다. 

 webkitDebugProxyPortios-webkit-debug-proxy: 실제 장치에서 webview 및 Safari 테스트를 위해 Appium은 특정 포트의 연결을 중재하는 작은 서비스를 실행합니다 . 다시 한번 말하지만, 여러 테스트 스레드가 동일한 포트에서 이 서비스와 통신을 시도하지 않는지 확인하세요.                                    





작가의 이전글 [앱자동화(2)](for Mac) appium 자동화
브런치는 최신 브라우저에 최적화 되어있습니다. IE chrome safari