再談 win32 程式的 UI 測試

來源:互聯網
上載者:User

接著上一篇的話題,因為要為 win32 程式寫 UI 測試,自已也摸索出來一個大致的架構。在這裡做一個小結:

 

以下代碼都發表在公有領域(http://zh.wikipedia.org/zh-cn/Public_domain),你可以自由地使用它們。

 

1. 首先,你需要建立進程:

 

{<br /> TCHAR cmdLine[1] = _T("");<br /> STARTUPINFO si;</p><p> ZeroMemory(&si, sizeof(STARTUPINFO));<br /> ZeroMemory(&piPlanet, sizeof(PROCESS_INFORMATION));</p><p> si.cb = sizeof(STARTUPINFO);<br /> si.dwFlags = STARTF_USESHOWWINDOW;<br /> si.wShowWindow = SW_NORMAL;<br /> BOOL bRet = ::CreateProcess(_T("Planet.exe"), cmdLine, NULL, NULL, FALSE, CREATE_DEFAULT_ERROR_MODE | NORMAL_PRIORITY_CLASS, NULL, NULL, &si, &piPlanet);<br /> ASSERT(bRet);<br />}

 

建立進程後,PROCESS_INFORMATION 結構體中就有了進程 id 和主線程 id 。

 

2. 獲得主視窗控制代碼

 

主要通過 EnumWindows 來實現,如果視窗 title 是固定的,那麼也可以用 FindWindowEx 。我這裡由於 title 和 class name 都未知,用了一種比較搓的辦法:先通過線程 id 隨便找一個視窗,再用 GetParent 擷取最頂層的視窗

 

// 一個回呼函數,相當於 EnumWindows 的過濾器<br />static BOOL CALLBACK findWindowThreadIdProc(HWND hWnd, LPARAM param)<br />{<br /> DWORD id = ::GetWindowThreadProcessId(hWnd, NULL); // 根據 HWND 得到線程id<br /> if (id == (DWORD) param)<br /> {<br /> hWndFound = hWnd;<br /> return FALSE;<br /> }<br /> return TRUE;<br />}</p><p>{<br /> hWndFound = NULL;<br /> // 找到指定的線程的第一個視窗:<br /> ::EnumWindows(findWindowThreadIdProc, piPlanet.dwThreadId);<br /> HWND hTmp;<br /> // 迴圈找到最頂層的視窗:<br /> while ((hTmp = ::GetParent(hWndFound)) != NULL)<br /> {<br /> hWndFound = hTmp;<br /> }<br />}

 

當然,如果你提前就知道視窗的 class name ,就可以直接在回呼函數中指定這個條件。

 

順便說一下如何在 MFC 程式中指定 class name :讓你的 CMainFrame 繼承來自 CWnd 的 PreCreateWindow 函數,這個函數將在 MFC 調用 CreateWindow 之前調用:

 

BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs)<br />{<br /> if (!CFrameWnd::PreCreateWindow(cs))<br /> return FALSE;</p><p> WNDCLASS wndclass;<br /> ::GetClassInfo(::AfxGetInstanceHandle(), cs.lpszClass, &wndclass);<br /> wndclass.lpszClassName= _T("PlanetMainFrame"); // 將 class name 設為指定的值<br /> VERIFY(::AfxRegisterClass(&wndclass));<br /> cs.lpszClass = wndclass.lpszClassName;</p><p> return TRUE;<br />} // CMainFrame::PreCreateWindow(CREATESTRUCT& cs)

 

另外,可以通過 VS 內建的 spy++ 查看案頭上所有視窗的 class name 。

 

3. 類比點菜單

 

::PostMessage(hWnd, WM_COMMAND, MAKEWPARAM(CM_PROJECTPURCHASES, BN_CLICKED), NULL);<br />Sleep(1000);

 

hWnd 是你的視窗控制代碼,CM_PROJECTPURCHASES 是對應的菜單 ID 。注意要 Sleep 足夠的時間。

 

還要注意 PostMessage 和 SendMessage 的區別:SendMessage  必須要等相應程式處理完訊息之後才返回,而 PostMessage 是非同步,立即返回。所以 PostMessage 需要 Sleep,而 SendMessage 則不需要。

 

4. 獲得最表面的視窗

 

hWnd = ::GetForegroundWindow();

 

與 GetFocus() 不同,這個直接獲得直觀上最表層的那個視窗(比如點了菜單後彈出來的一個視窗),相當 imba 。而 GetFocus() 得到的控制代碼可能會是一個編輯框控制項。

 

5. 關閉視窗

 

#define closeWindowX(w) {::PostMessage(w, WM_CLOSE, 0, 0);Sleep(500);}

 

然後就是 GetDlgItem() 之流了,再加上上篇文章介紹的類比按鍵,基本上能搞定大部分的自動化 UI 測試工作。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.