포스트를 쓰는 기능에 대해서 UI 테스트 자동화를 하던 중, 다시 난관에 부딪혔다.
사진을 첨부하는 기능을 테스트 자동화하려 했는데, 사진을 첨부하는 영역이 input 태그가 아닌, button을 클릭하면 windows GUI 창이 열리는 형식이였다.
Selenium은 web을 컨트롤 할 수 있는 도구였기에 windows GUI를 컨트롤 할 수는 없었다.
이걸 어떻게 해야하나.. 하고 구글링을 하던 중 Autoit이라는 프로그램과 모듈을 알게 됐다.
Autoit은 Python의 모듈로, Python을 통해서 windows GUI를 컨트롤 할 수 있는 모듈이다. 모듈을 import한 후, Autoit 프로그램을 통해서 windows GUI들의 정보를 알아내어서 이를 기반으로 모듈의 명령문들로 핸들링하는 방식이다.
Autoit을 만나고 내가 목표로 했던 것이 가능하다는 희망이 생겼다. 그리고 Autoit을 더 검색하던 중, Python-UIAutomation-for-Windows라는 것을 알게 됐다. 포스트를 통해서 알게된 정보에 따르면 초기버전 windows의 GUI 객체 컨트롤은 Autoit으로 모두 가능했다. 하지만 windows의 버전이 올라감에 따라서 새로운 UI 요소를 그릴 수 있는 Library가 공개되었다. 그것이 .Net Framework 이다. 현재 대부분의 창들은 모두 .Net Framework 3.0 이후의 버전을 사용해서 그려지고 있다. 이에 따라 MS에서는 .Net Framework의 GUI 객체 컨트롤을 위해서 UIAutomation API를 공개했다. 이번에 새롭게 사용해봤고, 여기서 소개할 Python-UIAutomation-for-Windows는 UIAutomation API를 Python에서 사용할 수 있도록 하게 해주는 Library이다.
추가적으로, 현재 대부분의 RPA(Robotic Process Automation)툴들, 특히 windows 기반의 툴들은 UIAutomation API를 기반으로 만들어져있다고 한다.
참고로했던 포스트를 따라하였다. 그러나 그때와 달라진 부분들이 있어 간단하게 이 포스트에 작성하고자 한다.
설치는 Python을 기준으로 설치합니다.
공식 배포처에서 설치 파일을 다운로드 받습니다.
https://github.com/mhammond/pywin32/releases
자신의 Python 버전과 맞는 버전의 파일을 다운로드 받아야합니다.
저는 python3.10에 amd64를 사용하고 있기에 위 파일을 다운로드 받았습니다.
2-1. 자신의 python 버전을 확인하려면 cmd에서 'python'이라고 입력하면 됩니다.
포스트에 따르면 관리자 권한으로 설치 파일을 실행시키고, 설치를 진행합니다.
이때, 설치 결과 화면이 빈 화면으로 나온다면 설치가 정상적으로 되지 않은 것이라고 합니다.
(관련 스크린 샷을 확인하려면 참조에 있는 해당 포스트를 확인해주세요.)
그럴 때에는 cmd를 관리자 권한으로 실행합니다.
Python 설치 폴더 내의 Scripts로 cd 명령을 이용해 이동합니다.
cmd에서 python pywin32_postinstall.py -install 명령을 입력합니다.
ide에서 uiautomation 모듈을 설치합니다. 저는 pycharm을 이용합니다.
inspect.exe를 다운로드 받습니다. 참조 포스트대로 다운로드 받는게 정석인것 같은데, 저는 따로 실행 파일만 다운받아서 사용했습니다. 포스트와 파일 모두 첨부해놓도록 하겠습니다.
참조 포스트 : https://technote.kr/348
x86 실행 파일 다운로드 : 다운로드
x64 실행 파일 다운로드 : 다운로드
실행 파일 다운로드 페이지 : https://github.com/yinkaisheng/Python-UIAutomation-for-Windows/tree/master/inspect
inspect.exe를 실행 후, windows GUI에 마우스 오버하거나 클릭하면 해당 GUI에 대한 정보들을 볼 수 있습니다. 예를 들어 계산기를 실행 후, 계산기의 숫자 패드를 클릭하면, 해당 숫자 패드의 type이 button임을, Name이 1임을 알 수 있습니다.
이제 다시 Python에서 uiautomation 모듈을 사용할 차례입니다.
아래는 제가 사용한 코드입니다. 각 라인에 대한 설명을 주석으로 기입해놨습니다.
import uiautomation as auto
uploader = auto.WindowControl(searchDepth=2, Name='열기')
if not uploader.Exists(3, 1):
logging.info("열기 창이 열리지 않았습니다.")
raise
uploader.EditControl(Name="파일 이름(N):").SendKeys('첨부할 이미지 파일의 경로~~/image.png')
uploader.ButtonControl(Name="열기(O)").Click()
0 depth는 windows의 객체 영역으로 우리가 잘 알고 있는 시작 메뉴 bar 같은 영역입니다.
1 depth는 windows 위에 떠 있는 창과 우리가 실행시킨 프로그램과 같은 영역입니다.
그 이하의 n depth들도 존재합니다. 내가 찾고자 하는 객체의 depth를 확인하기 위해서는inspect.exe를 이용해야합니다. inspect를 tree 구조로 실행시키면 현재 실행되어 있는 windows 객체들을 tree 구조로 확인 가능하며, 확인할 수 있습니다. 여기에 노출되는 가장 상위가 1 depth, 그 아래가 2,3,4...의 depth를 나타냅니다. 따라서 우리가 찾고자 하는 GUI를 실행시키고 마우스 오버나 클릭하여 해당 GUI를 inspect에 노출시키고, 그 객체가 inspect에서 몇 번째 depth에 위치하고 있는지 확인하여 우리의 searchDepth를 정할 수 있습니다.
위 예시를 보면, 제가 찾고자 하는 객체는 크롬 창에서 열린 '열기'창 입니다.
이때, 크롬 브라우저가 1 depth에 위치하게 되고, '열기' 창이 그 아래에 열렸기 때문에 크롬 브라우저 아래의 2 depth에 위치하는 것 입니다.
따라서 저는 이 '열기' 창을 찾기 위해서
uploader = auto.WindowControl(searchDepth=2, Name='열기')
를 한 것입니다. 2 depth에서 Name이 '열기'인 윈도우를 찾아서 컨트롤 하겠다는거죠.
사실 제가 보려고 마구잡이로 기록하다보니 모자란 정보들이 많습니다.
아래 참조 내용도 읽어보시고 부족하거나 틀린 내용이 있다면 알려주시면 감사하겠습니다.
Python-UIAutomation-for-Windows를 접하게 된 포스트입니다. 도움이 많이 됩니다.
https://velog.io/@chacha/Autoit-Python-Autoit-%EC%84%A4%EC%B9%98-%EB%B0%8F-%EC%8B%A4%ED%96%89
Python-UIAutomation-for-Windows Release git 입니다.
https://github.com/mhammond/pywin32/releases
Autoit에 대해 알게 됐던 포스트입니다.
https://kissi-pro.tistory.com/39
inspect.exe 파일을 다운로드 받을 수 있는 git 입니다.
https://github.com/yinkaisheng/Python-UIAutomation-for-Windows/tree/master/inspect