don't stop believing

Appium Unity 앱 Client 작성 1 (with OpenCV) 본문

Testing Automation/Appium

Appium Unity 앱 Client 작성 1 (with OpenCV)

Tongchun 2018. 8. 16. 20:24

Appium으로 Unity App을 테스트 해보겠습니다.

Unity App은 통 이미지로 인식하기 때문에 OpenCV를 사용해 이미지를 찾아 처리해야 합니다.


먼저 아래 순서를 확인해 주세요.


1. Windows에 Appium이 설치되어 있어야 하구요.

http://dejavuqa.tistory.com/222


2. Device와 연결되어 있어야 합니다.

http://dejavuqa.tistory.com/224


3. Python으로된 Appium Client까지 작성되어 있다면..

http://dejavuqa.tistory.com/225


4. OpenCV를 설치 하세요.

http://dejavuqa.tistory.com/228


5. OpenCV가 제대로 동작하는지도 확인했다면...

http://dejavuqa.tistory.com/99



OpenCV를 이용한 Unity App 테스트는 다음과 같은 동작을 합니다.

1. Appium으로 Device에 App을 실행 시킨다.

2. Appium으로 Device의 Screenshot을 찍는다.

3. OpenCV로 Screenshot과 찾으려는 이미지를 비교한다.

4. Screenshot에서 찾으려는 이미지가 있을 경우 좌표값을 확인한다.

5. Appium에서 좌표값을 이용해 Click 등의 액션을 수행한다.


이번에는 Appium과 OpenCV를 어떻게 사용하는지 확인해 보겠습니다.

게임을 실행한 뒤에 카카오 로그인 버튼을 클릭하는 방법을 먼저 확인해 보겠습니다.


이제 Unity App을 실행시킬 준비를 하겠습니다.

게임을 Device에서 실행시키고 카카오 로그인이 나오면 스크린샷을 찍습니다.


Device별로 해상도가 다르기 때문에 테스트하려는 Device에서 스샷을 찍어야 합니다.


저는 Galaxy S7 (Android 6.0.1)에 테스트할 App을 설치하고 스크린샷을 찍었습니다.

Galaxy S7은 해상도가 2560 x 1440 입니다.



Device에서 찍은 스크린샷을 PC로 옮겨 찾으려는 이미지를 잘라냅니다.

Galaxy의 경우 스크린샷 이미지의 경로는 Samsung Galaxy S7\Phone\DCIM\Screenshots에 있습니다.


스크린샷에서 노란색의 '카카오계정으로 로그인' 버튼을 클릭해야 합니다.

찾으려는 로그인 버튼을 이미지 편집 툴로 잘라냅니다.



잘라낸 이미지는 SearchImages라는 폴더에 넣습니다.



이제 Python으로 Appium Client를 작성할 차례입니다.

아래와 같이 작성합니다.


'''
Kakao Game SDK Test App
Device: V10 (LGF600Kb1134738)
'''
import unittest
import os
from appium import webdriver
from time import sleep
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC
from selenium.common.exceptions import NoSuchElementException

# opencv를 사용하기 위해 아래 모듈을 import합니다.
import cv2
import numpy as np
import time, datetime


class TS():
    def makeTS(self):
        return str(int(datetime.datetime.now().timestamp()))

class GrandchaseLoginOutTest(unittest.TestCase):

    def setUp(self):
        
        # Kakao Game SDK Test App 경로
        app = os.path.join(os.path.dirname(__file__), 'D:\\Test_Appium\\Grand', 'resigned_com.kakaogames.grdchase_1.8.4_qa.apk')
        app = os.path.abspath(app)

        # Set up appium
        # Appium 서버의 포트는 4001로 지정합니다.
        # 그리고 desired_capabilities에 연결하려는 디바이스(V10)의 정보를 넣습니다.
        self.driver = webdriver.Remote(
            command_executor='http://127.0.0.1:4001/wd/hub',
            desired_capabilities={
                'app': app,
                'platformName': 'Android',
                'platformVersion': '6.0.1',
                'deviceName': 'Galaxy S7',
                'automationName': 'Appium',
                'newCommandTimeout': 300,
                'appPackage': 'com.kakaogames.grdchase',
                'appActivity': 'com.kog.grandchase.Main',
                'udid': 'ce021602746c472502'
            })

    def test_search_field(self):

        ts = TS()

        # appiun의 webdriver를 초기화 합니다.
        driver = self.driver

        # selenium의 WebDriverWait을 사용합니다. element가 나올때 까지 최고 20초까지 기다립니다.
        wait = WebDriverWait(driver, 20)

        # 게임 실행 후 Asset을 다운로드할때까지 기다립니다.
        sleep(150)

        # python 파일이 실행된 현재 경로를 확인합니다.
        directory = '%s/' % os.getcwd()

        # appium에서 screenshot을 찍고 저장할 파일 이름을 생성합니다.
        screenshot = '%s-screenshot.png' % ts.makeTS()
        detectshot = '%s-detect.png' % ts.makeTS()

        # appium으로 스크린샷을 찍고 현제 경로에 저장합니다.
        driver.save_screenshot(directory + screenshot)

        # opencv로 스크린샵을 흑백으로 읽어들입니다.
        sourceimage = cv2.imread(screenshot, 0)

        # 찾으려는 이미지도 opencv로 읽어들입니다. (흑백: grayscale)
        template = cv2.imread('searchimages\\kakaologin.png', 0)

        # 찾으려는 이미지의 폭과 높이를 확인합니다.
        w, h = template.shape[::-1]

        # opencv에서 이미지 매칭할 방법을 선택합니다. TM_CCOEFF으로 이미지를 찾겠습니다.
        method = eval('cv2.TM_CCOEFF')

        # opencv의 matchTemplate() 함수를 사용해 스크린샷 이미지에서 찾으려는 이미즈를 확인합니다.
        res = cv2.matchTemplate(sourceimage, template, method)

        '''
        matchTemplate() 함수의 결과값을 minMaxLoc() 함수에 넣습니다.
        이미지 매칭에 대한 최소값(min_val: 가장 비슷하지 가중치 값)과 
        최대값(max_val: 가장 비슷한 가중치 값)을 확인합니다.
        가중치가 낮은 곳의 정사각형의 왼쪽 위 모서리 좌표(min_loc)과 
        가중치가 큰 곳의 정사각형의 왼쪽 위 모서리 좌표(max_loc)를 확인할 수 있습니다.
        '''
        min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(res)

        # max_loc을 이용해 찾으려는 이미지의 외쪽 위 모서리 좌표와 오른쪽 아래 모서리 좌표를 확인합니다.
        top_left = max_loc
        bottom_right = (top_left[0] + w, top_left[1] + h)

        # 중앙 좌표도 확인합니다. 중앙 좌표는 x, y이므로 튜플로 확인합니다.
        center = (top_left[0] + int(w/2), top_left[1] + int(h/2))

        # 찾으려는 이미지가 맞는지 원본인 스크린샷 이미지에 사각형으로 표시해 봅니다.
        color = (0, 0, 255)
        cv2.rectangle(sourceimage, top_left, bottom_right, color, thickness=8)
        cv2.imwrite(detectshot, sourceimage)

        # appium(driver)의 tap 명령으로 중안 좌표를 클릭(탭)합니다.
        driver.tap([center])

        # 30초 동안 기다립니다.
        sleep(30)


    def tearDown(self):
        self.driver.quit()



if __name__ == '__main__':
    suite = unittest.TestLoader().loadTestsFromTestCase(GrandchaseLoginOutTest)
    unittest.TextTestRunner(verbosity=2).run(suite)

위 코드를 실행한 후 폴더에 아래와 같이 이미지가 저장되었습니다.




'카카오계정으로 로그인'버튼에 박스가 그려진 것을 확인할 수 있습니다.


위 코드에서 openCV를 이용한 이미지 매칭 기능을 별도의 함수로 정리하면 아래와 같이 될 수 있습니다.


'''
Kakao Game SDK Test App
Device: V10 (LGF600Kb1134738)
'''
import unittest
import os
from appium import webdriver
from time import sleep
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC
from selenium.common.exceptions import NoSuchElementException

# opencv를 사용하기 위해 아래 모듈을 import합니다.
import cv2
import numpy as np
import time, datetime

class Matching():

    def detectimage(self, screenshotPath, detectImagePath):

        sourceimage = cv2.imread(screenshotPath, 0)
        template = cv2.imread(detectImagePath, 0)

        w, h = template.shape[::-1]

        method = eval('cv2.TM_CCOEFF')
        res = cv2.matchTemplate(sourceimage, template, method)
        min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(res)

        print('max_val: %d' % max_val)

        top_left = max_loc
        bottom_right = (top_left[0] + w, top_left[1] + h)
        center = (top_left[0] + int(w/2), top_left[1] + int(h/2))

        color = (0, 0, 255)
        cv2.rectangle(sourceimage, top_left, bottom_right, color, thickness=8)

        detectshotPath = screenshotPath[:-4] + '-detect.png'
        cv2.imwrite(detectshotPath, sourceimage)

        return center


class GrandchaseLoginOutTest(unittest.TestCase):

    def makeTS(self):
        return str(int(datetime.datetime.now().timestamp()))

    def strDatetime(self):
        return str(datetime.datetime.now().strftime("%Y%m%d%H%M"))

    def setUp(self):
        
        # Kakao Game SDK Test App 경로
        app = os.path.join(os.path.dirname(__file__), 'D:\\Test_Appium\\Grand', 'resigned_com.kakaogames.grdchase_1.8.4_qa.apk')
        app = os.path.abspath(app)

        # Set up appium
        # Appium 서버의 포트는 4001로 지정합니다.
        # 그리고 desired_capabilities에 연결하려는 디바이스(V10)의 정보를 넣습니다.
        self.driver = webdriver.Remote(
            command_executor='http://127.0.0.1:4001/wd/hub',
            desired_capabilities={
                'app': app,
                'platformName': 'Android',
                'platformVersion': '6.0.1',
                'deviceName': 'Galaxy S7',
                'automationName': 'Appium',
                'newCommandTimeout': 300,
                'appPackage': 'com.kakaogames.grdchase',
                'appActivity': 'com.kog.grandchase.Main',
                'udid': 'ce021602746c472502'
            })

    def test_search_field(self):

        matching = Matching()

        # 스크린샷을 저장할 폴더를 생성합니다.
        test_folder_name = self.strDatetime()
        currentPath = '%s/' % os.getcwd()
        test_Directory = currentPath + test_folder_name + '/'
        
        if not os.path.exists(test_Directory):
            os.makedirs(test_Directory)

        driver = self.driver
        wait = WebDriverWait(driver, 20)

        sleep(150)

        # '카카오계정으로 로그인' 이미지 찾아 중앙을 tap 한다.
        screenshotPath = test_Directory + '%s-screenshot.png' % self.makeTS()
        detectImagePath = currentPath + 'searchimages/kakaologin.png'
        driver.save_screenshot(screenshotPath)
        
        center = matching.detectimage(screenshotPath, detectImagePath)
        driver.tap([center])

        # 30초 동안 기다립니다.
        sleep(30)


    def tearDown(self):
        self.driver.quit()



if __name__ == '__main__':
    suite = unittest.TestLoader().loadTestsFromTestCase(GrandchaseLoginOutTest)
    unittest.TextTestRunner(verbosity=2).run(suite)





Comments