본문 바로가기

TA(Test Automation)

googleTest + win app driver + vs2022

728x90

 

mfcbuttontest.zip
0.07MB
MfcButtonTest_Auto.zip
0.01MB

 

 

vcpkg 설치 이후, PowerShell에서 gtest를 설치하고 연동하는 과정을 요약해드립니다.

✅ GoogleTest 설치

cd D:\tools\vcpkg
.\vcpkg install gtest:x64-windows

※ gtest:x64-windows → 64비트용 gtest 설치

 

✅ Visual Studio 연동

.\vcpkg integrate install
  • Visual Studio 프로젝트에서 #include <gtest/gtest.h> 바로 사용 가능
  • 자동으로 gtest.lib, gtest_main.lib 링크됨
  • 경로 추가나 링커 설정 필요 없음

 

✅ 환경 구성 흐름

1. vcpkg 설치 및 환경변수 설정
2. PowerShell에서 `vcpkg install gtest:x64-windows`
3. `vcpkg integrate install`로 VS 자동 연동
4. VS 프로젝트에서 바로 gtest 사용 가능

 

 

 

 

아래는 이번 작업을 통해 구성된 MFC UI 앱 + GoogleTest 실행기 + WinAppDriver 자동화 테스트
📂 간단한 디렉토리 구조와 각 파일의 역할 설명입니다.


✅ 디렉토리 구조

MyTestSolution/
├── mfcbuttontest/                    # 🎨 MFC UI 앱 (버튼 제공)
│   ├── mfcbuttontest.sln            # 전체 솔루션 파일
│   ├── mfcbuttontest.vcxproj        # MFC 앱 프로젝트 파일
│   ├── mfcbuttontest.cpp            # MFC 앱 진입점
│   ├── mfcbuttontestDlg.cpp         # 다이얼로그 로직
│   ├── mfcbuttontestDlg.h
│   ├── resource.h / .rc             # 버튼 리소스 (IDC_BTN_OK = 1000)
│   └── ... (기타 stdafx, pch 등)
│
├── MfcButtonTest_Auto/              # 🧪 테스트 실행기 (콘솔 앱)
│   ├── MfcButtonTest_Auto.vcxproj   # 콘솔 테스트 실행기 프로젝트
│   ├── main.cpp                     # GoogleTest 진입점
│   ├── MfcAppTest.cpp               # 테스트 본문 (WinHTTP 사용)
│   ├── MfcAppTest.h                 # 세션/클릭 함수 선언
│   └── (gtest/lib 포함되거나 vcpkg로 연결)
│
└── WinAppDriver/                    # ▶️ 외부 실행 프로그램
    └── WinAppDriver.exe             # 반드시 수동 실행 필요

✅ 각 역할

폴더/파일 설명

mfcbuttontest/ MFC UI 앱. 버튼(ID 1000)을 화면에 표시
mfcbuttontestDlg.cpp 다이얼로그 동작 정의. OnInitDialog()에서 버튼 생성
resource.h / .rc IDC_BTN_OK = 1000 정의
MfcButtonTest_Auto/ GoogleTest 기반 콘솔 테스트 실행기
main.cpp InitGoogleTest() + RUN_ALL_TESTS()
MfcAppTest.cpp WinHTTP로 WinAppDriver와 통신, 앱 실행 및 버튼 클릭
WinAppDriver.exe Microsoft 공식 UI 자동화 서버. 수동 실행 필요 (/session 기반 REST API)

✅ 실행 흐름

(1) WinAppDriver.exe 실행
       ↓
(2) MfcButtonTest_Auto.exe 실행
       ↓
    [main.cpp] RUN_ALL_TESTS()
       ↓
    [MfcAppTest.cpp]
        - POST /session → mfcbuttontest.exe 실행
        - POST /element → 버튼(ID=1000) 찾기
        - POST /click → 클릭
       ↓
    테스트 통과 → 종료

✅ 필요 구성

항목 필요 여부 설치 방식

Visual Studio 2022 MFC + Desktop C++ 워크로드
GoogleTest vcpkg install gtest or 직접 빌드
WinAppDriver https://github.com/microsoft/WinAppDriver/releases
CPR / nlohmann/json 사용 안 함 (WinHTTP + string 파싱만 사용)

 

 

 

//main.cpp

#include <gtest/gtest.h>

int main(int argc, char** argv)
{
    ::testing::InitGoogleTest(&argc, argv);
    return RUN_ALL_TESTS();
}

 

//MfcAppTest.h

#pragma once
#include <string>

bool LaunchMfcAppViaWinAppDriver(std::string& sessionId);
bool ClickButtonByAccessibilityId(const std::string& sessionId, const std::string& elementId);

 

//MfcAppTest.cpp

#include "MfcAppTest.h"
#include <gtest/gtest.h>
#include <windows.h>
#include <winhttp.h>
#include <iostream>
#include <sstream>

#pragma comment(lib, "winhttp.lib")

std::string ToUtf8(const std::wstring& wstr)
{
    if (wstr.empty()) return {};

    int size = WideCharToMultiByte(CP_UTF8, 0, wstr.c_str(), -1, nullptr, 0, nullptr, nullptr);
    if (size <= 0) return {};

    std::string result(size - 1, 0); // null 포함한 크기 -1 (std::string에는 null 불필요)
    WideCharToMultiByte(CP_UTF8, 0, wstr.c_str(), -1, &result[0], size, nullptr, nullptr);

    return result;
}


bool HttpPost(const std::wstring& path, const std::string& body, std::string& response)
{
    HINTERNET hSession = WinHttpOpen(L"WinAppDriverTest/1.0", WINHTTP_ACCESS_TYPE_NO_PROXY, nullptr, nullptr, 0);
    if (!hSession) return false;

    HINTERNET hConnect = WinHttpConnect(hSession, L"127.0.0.1", 4723, 0);
    if (!hConnect) return false;

    HINTERNET hRequest = WinHttpOpenRequest(hConnect, L"POST", path.c_str(), nullptr, WINHTTP_NO_REFERER,
        WINHTTP_DEFAULT_ACCEPT_TYPES, 0);

    std::wstring headers = L"Content-Type: application/json\r\n";
    const char* bodyData = body.c_str();

    BOOL bResult = WinHttpSendRequest(
        hRequest,
        headers.c_str(), (DWORD)-1,
        const_cast<LPVOID>(static_cast<const void*>(bodyData)), // ✅ 핵심 수정
        (DWORD)body.size(),
        (DWORD)body.size(),
        0
    );

    if (!bResult || !WinHttpReceiveResponse(hRequest, nullptr)) return false;

    std::stringstream ss;
    DWORD dwDownloaded = 0;
    do {
        char buffer[4096];
        if (!WinHttpReadData(hRequest, buffer, sizeof(buffer), &dwDownloaded)) break;
        ss.write(buffer, dwDownloaded);
    } while (dwDownloaded > 0);

    response = ss.str();

    WinHttpCloseHandle(hRequest);
    WinHttpCloseHandle(hConnect);
    WinHttpCloseHandle(hSession);
    return true;
}


bool LaunchMfcAppViaWinAppDriver(std::string& sessionId)
{
    std::string response;
    std::string body = R"({
        "desiredCapabilities": {
            "platformName": "Windows",
            "deviceName": "WindowsPC",
            "app": "D:\\Users\\ahrns\\source\\repos\\mfcbuttontest\\x64\\Debug\\mfcbuttontest.exe"
        }
    })";

    if (!HttpPost(L"/session", body, response)) return false;

    std::string key = "\"sessionId\":\"";
    auto pos = response.find(key);
    if (pos == std::string::npos) return false;

    pos += key.length();
    auto end = response.find('"', pos);
    if (end == std::string::npos) return false;

    sessionId = response.substr(pos, end - pos);
    return !sessionId.empty();
}

bool ClickButtonByAccessibilityId(const std::string& sessionId, const std::string& elementId)
{
    std::string response;
    std::ostringstream ss;
    ss << R"({"using": "accessibility id", "value": ")" << elementId << R"("})";

    std::wstring elementPath = L"/session/" + std::wstring(sessionId.begin(), sessionId.end()) + L"/element";
    if (!HttpPost(elementPath, ss.str(), response)) return false;

    std::string key = "\"ELEMENT\":\"";
    auto pos = response.find(key);
    if (pos == std::string::npos) return false;

    pos += key.length();
    auto end = response.find('"', pos);
    if (end == std::string::npos) return false;

    std::string eid = response.substr(pos, end - pos);

    std::wstring clickPath = L"/session/" + std::wstring(sessionId.begin(), sessionId.end()) + L"/element/"
        + std::wstring(eid.begin(), eid.end()) + L"/click";

    return HttpPost(clickPath, "{}", response);
}

TEST(MfcAppTest, LaunchAndClickButton)
{
    std::string sessionId;
    ASSERT_TRUE(LaunchMfcAppViaWinAppDriver(sessionId)) << "앱 실행 실패";
    ASSERT_TRUE(ClickButtonByAccessibilityId(sessionId, "1000")) << "버튼 클릭 실패";
}

 

 

 

 

728x90