mitmproxy를 활용해 구글 애널리틱스 테스트 자동화하기

개요

안녕하세요. LINE 대만에서 LINE TODAY 관련 자동화 QA 엔지니어로 일하고 있는 Edward와 Miki입니다. 이번 글에서는 LINE TODAY에서 웹사이트를 최적화하기 위해 사용하는 구글 애널리틱스(Google Analytics, GA)의 테스트 자동화 방법에 대해 알아보려고 합니다.

LINE TODAY를 위한 GA 테스트

GA는 웹사이트 트래픽을 추적하는 가장 보편적인 방법입니다. GA를 이용하면 특정 페이지의 방문자 수는 물론, 방문자 수를 기기 모델이나 나라별로 정렬한 정보 등과 같은 중요한 정보를 알 수 있습니다. 운영 팀에선 이런 정보를 기반으로 방문자 행동을 분석합니다. 분석이 끝나면, 운영 팀은 통계적 관점에서 방문자에게 좀 더 나은 사용자 경험을 줄 수 있는 방향으로 웹사이트의 콘텐츠와 디자인을 최적화할 수 있습니다.  

우리는 운영 팀이 GA에서 생성된 LINE TODAY 앱에 대한 보고서와 내용을 신뢰할 수 있도록 GA 추적 코드가 제대로 작동하고 커스텀 dimension이 정확히 설정되었는지 확인하고 싶었습니다. 그래서 매 릴리스 후에, LINE TODAY 개발 팀과 QA 팀에선 GA 이벤트가 정확하게 보내졌는지 검증하기 위해 proxy 도구와 직접 만든 parser 도구를 사용하고 있습니다. 

mitmproxy란?

mitmproxy는 트래픽을 추적하기 위한 중간 프록시로, Python으로 만들어진 편리한 네트워크 분석 도구입니다. 편리하다고 하는 이유는 추후 분석 시 유용한 Python 스크립트 애드온 작성이 가능하기 때문입니다. 콘솔 인터페이스를 이용해서 원하는 트래픽을 확보하고 점검할 수 있습니다. 또한 mitmproxy 애드온 메커니즘은 개발자가 원하는 트래픽 정보를 확보할 수 있도록 API를 제공하고 있습니다.

GA 테스트 자동화 구조와 흐름

아래 그림은 LINE TODAY 앱에서 mitmproxy와 애드온 메커니즘이 어떻게 GA 트래픽을 가져오고 있는지 보여줍니다.

StepsDescription
1~2사용자가 클라이언트에서 뉴스 기사 페이지와 같은 LINE TODAY 페이지로 들어옵니다.
 3클라이언트는 LINE TODAY GA 페이지뷰나 이벤트를 GA 서버로 보냅니다.
4이때 Python 스크립트 애드온이 끼어들어 mitmproxy의 동작을 바꿔서(모든 GA 페이지뷰와 이벤트를 가로챔) 추후 분석을 위해 요청을 추적합니다.
5mitmproxy가 GA 서버로 요청을 보냅니다.

GA 테스트 자동화 방법

이제 mitmproxy를 이용해서 GA 이벤트가 제대로 보내졌는지 검증할 수 있는 두 가지 방법을 소개드리겠습니다. 하나는 실시간 아웃풋 로그를 제공하는 반자동화(semi-automated)된 방법이고요. 다른 하나는 전체 결과에 대한 테스트를 제공하는 완전 자동화(full-automated)된 방법입니다.

반자동화 방법

반자동화된 모니터링 도구를 사용하여 QA 이벤트가 적절하게 전송되었는지 실시간으로 확인할 수 있습니다. 

설정

설정에 들어가기 전에, 우선 mitmproxy와 CA certificate를 설치해야 합니다. 설치 후 프록시 설정에서 원하는 port를 설정합니다(이번 글에선 8081을 사용합니다).

반자동화 테스트를 설정하는 전체 흐름은 아래와 같습니다.

  1. 원하는 트래픽을 가로챌 수 있도록 Python 스크립트로 애드온을 구현합니다.
  2. 애드온과 함께 mitmproxy를 실행합니다.
  3. 자신의 기기를 사용해 웹페이지를 방문하고 콘솔에서 GA 트래픽을 확인합니다.
  4. 실시간 아웃풋 로그를 확인하여 검증합니다. 

아래는 GA 페이지뷰와 이벤트 트래픽을 추적하는 Python 스크립트 애드온의 예시입니다. GA 요청이 발생하면 요청은 mitmproxy의 내부 로깅 메커니즘을 우회하게 됩니다. 아웃풋 로그는 mitmdump를 통해 콘솔에 나타납니다.

from mitmproxy import ctx
import mitmproxy.log
import mitmproxy.proxy.protocol
 
class Tracker:
    def __init__(self):
    ..........
    ....
    ......
 
    def request(self, flow):
        logRequest = None
         
        # 1. 어떤 이벤트 유형을 모니터할 지 정합니다. 예시) 페이지뷰와 이벤트
        self.event_type = ['pageview', 'event']
         
        # 2. 여기에 원하는 dimension을 적습니다. 각자의 요구사항에 따라 다를 것입니다.
        checkCds = ['type', 'dp', 'cd17', 'cd4']
         
        # 3. GA 서버로 보내진 로그를 분석합니다.
        for a_key in flow.request.query.keys():
            if ('google-analytics' in flow.request.url):
                val = flow.request.query[a_key]
                if (a_key == 'type' and val in self.event_type):
                    ctx.log.info('Host: ' + flow.request.url)
                    ctx.log.info('%s = %s ' % (a_key, val))
                    logRequest = True
                elif (a_key in checkKeys and logRequest):
                    ctx.log.info('%s = %s ' % (a_key, val))
 
    def done(self):
        """
            Called when the addon shuts down, either by being removed from
            the mitmproxy instance, or when mitmproxy itself shuts down.
        """
 
addons = [
    Tracker()
]

mitmdump는 mitmproxy와 커맨드 라인 세트입니다. mitmdump가 tcpdump와 비슷한 기능을 제공해주고 있어서, 로그를 기록할 수 있고 Python 스크립트로 트래픽을 기록할 수 있습니다.

$ mitmdump -s [Your_Parser_File].py -p 8081 --set flow_detail=0

-p 옵션은 프록시 포트를 설정하는 옵션입니다. 여기선 8081로 설정했습니다.  --set flow_detail=0 옵션은 mitmdump flow의 상세 표시 수준을 설정합니다. 0으로 설정하면 거의 아무것도 나타나지 않습니다.

실시간 로그

사용자가 다른 카테고리에서 영화 메인 페이지로 들어와 정착한 경우를 생각해보겠습니다. 그럼 아래와 같은 로그가 나타날 것입니다. 

# When a user clicks movie main page tab, the click event would be triggered.
 
--------------------------------------------------
Event sends to GA
--------------------------------------------------
Host: https://www.google-analytics.com/collect?v=xxxxx&t=event&_s=14&dl=https%3A%2F%2Ftoday.line.me%2FTW&ul=en-us&de=UTF-8&dt=LINE%xxxxx&tid=UA-xxxxxxxxx-1&_gid=&z=xxxxxxxxx
type = event
ea = portal_bar_click
el = bar_movie_click
cd17 = ios
cd4 = TW
..........
....
......
 
 
# The pageview event would be requested after event sent out.
--------------------------------------------------
Pageview sends to GA
--------------------------------------------------
Host: https://www.google-analytics.com/collect?v=1&_v=j68&a=xxxxxxxx&t=pageview&_s=15&dl=https%3A%2F%2Ftoday.line.me%2FTW&dp=TW_portal_%E9%9B%BB%E5%BD%B1&ul=en-us&de=UTF-8&dt=LINE%20TODAY&sd=24-bit&sr=2560x1440&vp=2560x791&je=0&_u=SCCAAEABE~&jid=&gjid=&tid=UAxxxxxxxxx-1&z=xxxxxxxxxxx
type = pageview
dp = TW_portal_movie
cd17 = ios
cd4 = TW
..........
....
......

아래와 같이 실시간으로 로그를 확인할 수 있기 때문에 콘솔 아웃풋 로그를 통해 GA 요청의 모든 키가 정확한지 검증할 수 있습니다.

완전 자동화

GA 요청을 확인하려고 수동으로 테스트하는 시간을 줄이고자, mitmdump를 자동화 테스트의 한 부분으로 자동화 프레임워크에 통합합니다. 그런데 그런 테스트에서 페이지뷰가 제대로 보내졌다는 것을 어떻게 보장할 수 있을까요? 우리는 제대로 된 PV(page view) 로그를 파일로 기록할 수 있습니다. 그리고 테스트가 끝나면, parser 도구는 파일을 만들어 그 파일을 제대로 된 파일과 비교할 것입니다. 만약 두 파일이 동일하다면 이번 테스트에서 PV가 제대로 보내졌다고 말할 수 있습니다.

설정과 구현

완전 자동화된 방법이기 때문에 설정이나 구현할 필요가 없습니다. 단지 Git에서 코드를 가져와 실행하기만 하면 됩니다. 아래 다이어그램과 표를 참고하여 전체 프로세스를 확인해보시기 바랍니다.

StepsDescription
1mitmdump를 실행하기 위한 프로세스를 실행합니다.
2Selenium Webdriver를 구동하기 위해 또 하나의 프로세스를 실행합니다.
3Selenium Webdriver가 웹브라우저를 자동화합니다.
4–5자동화된 웹브라우저가 LINE TODAY 페이지를 탐색하면서 LINE TODAY GA 페이지뷰나 이벤트를 전송합니다.
6애드온은 추후 분석을 위해 필요한 GA 요청을 추적합니다.
모든 테스트가 완료되면, GA 로그를 아웃풋 파일로 모읍니다.
7mitmproxy는 요청을 GA 서버로 보냅니다.
8생성된 GA 로그 파일을 올바른 파일과 비교하고 결과를 보여줍니다.

예시

아래 예시는 프레임워크로 GUI테스트를 실행하면서 트래픽을 얻기 위해 Robot Framework와 mitmdump를 통합한 예시입니다. Mitmdump를 실행하기 위한 프로세스 구동 키워드를 Start Mitmdump Proxy Process로 설정했습니다.

Verify GA Pageview Event in PC Web
    Start Mitmdump Proxy Process
    # Here you can put the keywords to nevigate all the pages on your website
    # ..
    # ..
    # ..
    [Teardown]    Run Keywords    Terminate Mitmdump Proxy Process   Compare Two PC PV Files

또 다른 프로세스를 실행해서 GA를 확인하고자 하는 자신의 웹사이트 페이지를 탐색하도록 합니다. 테스트가 완료되면 mitmdump 프록시 프로세스를 종료시키고 생성된 PV 로그 파일을 올바른 파일과 비교하여 GA 추적 코드가 잘 작동했는지 확인합니다.

아래는 mitmdump 프로세스를 실행하기 위한 키워드를 생성하는 예시입니다. 테스트가 완료되면 in.txt 파일이 생성되고, 이 파일을 올바른 결과가 들어있는 파일과 비교하게 됩니다.

# Keyword
Start Mitmdump Proxy Process
    ${result} =  Start Process    mitmdump -s YOUR/FILE/PATH/xxx.py -p 8081 --set flow_detail=0 > in.txt    shell=True

만약 in.txt 파일과 올바른 결과를 가진 파일이 동일하다면 콘솔에서 아래와 같은 내용을 볼 수 있습니다.

결론

만약 여러분의 팀에서 GA가 웹사이트를 최적화하기 위한 중요한 도구로 쓰이고 있다면, 여러분은 GA 요청이 제대로 작동하고 있다는 것을 확인할 수 있는 도구가 필요할 것입니다. 또한 자동화 테스트 도구를 사용하여 GA를 검증하고 테스트가 매 릴리스 전에 Jenkins에서 자동으로 실행되도록 설정한다면 보고서의 신뢰도가 점점 높아질 것입니다. 여러분의 앱이나 웹사이트에서 트래픽을 가져올 때 mitmproxy를 한번 사용해보시기 바랍니다.

참조 자료

mitmproxy나 Robot Framework에 대한 좀 더 자세한 사항은 아래 링크에서 확인할 수 있습니다.

Related Post