UI 자동화의 한계성 보완하기

정태경·2022년 1월 16일
1
post-custom-banner

UI 자동화의 한계

UI 자동화 테스트를 구현하다보면 금새 한계를 맞닥들이게된다.
예를 들어 네이버 쇼핑의 구매 플로우를 UI 자동화 테스트로 구현했다고 가정해보자.

Selenium 또는 Appium 이 열심히 Element를 찾아 작성된 테스트 케이스를 실행할 것이다. 그러나 만약 Element 는 정상적으로 식별되고 있으나, 특정 API의 Status Code 에 에러가 있다거나 특정 리소스를 받아오지 못해 상품 정보가 표시되지 않는 상황이라면?

에러로 인하여 리소스를 받아오지 못하는 상황이더라도, UI 자동화 테스트 코드에서는 엘리먼트가 식별되고 사전에 작성된 테스트 스크립트에 문제가 없기 때문에 PASS 처리 될 것이다.

그럼 어떻게 이러한 상황을 보완할 수 있을까?

나는 browsermobproxy를 활용해보았다. browsermobproxy이란 일종의 Proxy 서버라고 생각하면 된다. HTTP 콘텐츠를 캡처하고, 성능 데이터를 HAR 파일 로 내보낼 수 있다. 특히나 Selenium 과 함께 활용이 가능하여 UI 자동화의 한계성을 보완해줄 수 있다.

예를 들면, 이러한 동작이 가능하다

  1. Selenium 자동화 코드 실행 전에 Python 코드로 browsermobproxy 서버를 띄우도록 구현한다.

  2. Selenium 자동화 코드를 실행한다.

  3. Selenium 자동화 코드 종료 후 browsermobproxy 서버를 종료하고 HAR 파일을 생성한다.

  4. HAR 파일의 HTTP Requset, Response 를 분석하여 에러를 확인한다.

Selenium 을 단독으로 사용했을 때와 뭐가 다른데?

browsermobproxySelenium이 자동화 코드를 실행하며 주고 받았던 HTTP 통신을 캡처해준다. 캡처된 HAR 파일을 열어 Status Code가 400 또는 500 에러 등이 발생한 이력이 있는지, 받아오지 못한 리소스 파일이 있는지 등을 확인해볼 수 있다.

따라서 Selenium 이 UI에 대한 테스트를 수행하는 동시에 browsermobproxy를 통해 HTTP 응답을 함께 검증할 수 있다.

어떻게 구현할 수 있을까? 테스트해보자!

  1. 먼저 browsermobproxy 파일을 다운받아 압축을 푼다 (링크)
    (압축푼 폴더 -> bin -> browsermob-proxy 요녀석을 사용할 것 이다)

  2. 파이썬 프로젝트 생성 후 pip 를 인스톨한다

pip install browsermobproxy
  1. 간단한 코드를 작성하여 테스트해보자
bmp_setting.py : 프록시 서버 실행과 응답 데이터 가공을 위한 메서드를 구현했다
from browsermobproxy import Server
import psutil
import time
from selenium import webdriver

def process_kill(name):
    """중복 실행중인 프로세스 종료"""

    for proc in psutil.process_iter():
        if proc.name() == name:
            proc.kill()

def capture_network_traffic(url):
    """프록시 서버 시작 및 네트워크 트래픽 캡쳐"""

    server = Server(path="/Users/taekyeong.jung/Downloads/browsermob-proxy-2.1.4/bin/browsermob-proxy",
                    options={'port': 8787})
    server.start()
    time.sleep(1)
    proxy = server.create_proxy()
    time.sleep(1)

    chrome_options = webdriver.ChromeOptions()
    chrome_options.add_argument("--headless")
    chrome_options.add_argument("--proxy-server={0}".format(proxy.proxy))
    chrome_options.add_argument('--ignore-certificate-errors')

    driver = webdriver.Chrome(executable_path="/Users/taekyeong.jung/Desktop/workspace/chromedriver",
                              chrome_options=chrome_options)

    proxy.new_har() # options={'captureContent': True} https://github.com/lightbody/browsermob-proxy

    driver.get(url)
    driver.quit()
    server.stop()
    return proxy.har

def check_response(response):
    """응답 데이터 가공"""
    entries = response['log']['entries']

    errors = []
    i = 0
    while i < len(entries):

        if entries[i]['response']['status'] >= 400: # http response 값이 400 이상이면 errors 배열에 추가

            dic = {
                    'method':     entries[i]['request']['method'],
                    'url':        entries[i]['request']['url'],
                    'status':     entries[i]['response']['status'],
                    'statusText': entries[i]['response']['statusText'],
                    'time':       entries[i]['time']
                }

            errors.append(dic)
        else:
            pass

        i = i + 1

    for i in errors:
        print(i)
test.py : bmp_setting.py 에 정의된 메서드를 활용하여 테스트 코드를 작성해보았다.
import bmp_setting as Setup


site = [
    'https://www.myrealtrip.com/',
    'https://flights.myrealtrip.com/',
    'https://www.myrealtrip.com/accommodations',
    'https://www.myrealtrip.com/rentacar',
    'https://www.myrealtrip.com/experiences/'
    ]

# 중복된 프로세스 제거
Setup.process_kill("browsermob-proxy")

# 프록시 서버 실행 후 네트워크 트래픽 캡쳐
for i in site:
    response = Setup.capture_network_traffic(i)
    Setup.check_response(response)

결과

아래와 같이 status Code가 400과 같거나 큰 녀석들이 필터되었다. Selenium 과 함께 활용하면 UI 테스트의 한계성을 보완하여 자동화 테스트 수행 및 리포트를 받을 수 있을 것으로 보인다.

{'method': 'GET', 'url': 'https://d32w679339tzui.cloudfront.net/landscapes/4750_large_square_1609204670.jpg?1609204670', 'status': 404, 'statusText': 'Not Found', 'time': 1579}
{'method': 'GET', 'url': 'https://d32w679339tzui.cloudfront.net/landscapes/4744_large_square_1609204668.jpg?1609204668', 'status': 404, 'statusText': 'Not Found', 'time': 1458}
{'method': 'GET', 'url': 'https://d32w679339tzui.cloudfront.net/landscapes/162_large_square_1609201732.jpg?1609201732', 'status': 404, 'statusText': 'Not Found', 'time': 1458}
{'method': 'GET', 'url': 'https://d32w679339tzui.cloudfront.net/landscapes/4751_large_square_1609204671.jpg?1609204671', 'status': 404, 'statusText': 'Not Found', 'time': 1489}
{'method': 'GET', 'url': 'https://d32w679339tzui.cloudfront.net/landscapes/770_large_square_1609202023.jpg?1609202023', 'status': 404, 'statusText': 'Not Found', 'time': 1462}
{'method': 'GET', 'url': 'https://d32w679339tzui.cloudfront.net/landscapes/4672_large_square_1609204639.jpg?1609204639', 'status': 404, 'statusText': 'Not Found', 'time': 1471}
{'method': 'GET', 'url': 'https://d32w679339tzui.cloudfront.net/landscapes/4606_large_square_1609204589.jpg?1609204589', 'status': 404, 'statusText': 'Not Found', 'time': 423}

reference
https://github.com/lightbody/browsermob-proxy#getting-started-standalone

profile
두나무 업비트 QA 엔지니어
post-custom-banner

0개의 댓글